Useful JVM Flags – Part 8 (GC Logging)
The last part of this series is about garbage collection logging and associated flags. The GC log is a highly important tool for revealing potential improvements to the heap and GC configuration or the object allocation pattern of the application. For each GC happening, the GC log provides exact data about its results and duration.
-XX:+PrintGC
The flag -XX:+PrintGC (or the alias -verbose:gc) activates the “simple” GC logging mode, which prints a line for every young generation GC and every full GC. Here is an example:
[GC 246656K->243120K(376320K), , secs]
[Full GC 243120K->241951K(629760K), , secs]
A line begins (in red) with the GC type, either “GC” or “Full GC”. Then follows (in blue) the occupied heap memory before and after the GC, respectively (separated by an arrow), and the current capacity of the heap (in parentheses). The line concludes with the duration of the GC (real time in seconds).
Thus, in the first line, 246656K->243120K(376320K) means that the GC reduced the occupied heap memory from 246656K to 243120K. The heap capacity at the time of GC was 376320K, and the GC took 0.0929090 seconds.
The simple GC logging format is independent of the GC algorithm used and thus does not provide any more details. In the above example, we cannot even tell from the log if the GC moved any objects from the young to the old generation. For that reason, detailed GC logging is more useful than the simple one.
-XX:+PrintGCDetails
If we use -XX:+PrintGCDetails instead of -XX:+PrintGC, we activate the “detailed” GC logging mode which differs depending on the GC algorithm used. We start by taking a look at the output produced by a young generation GC using the Throughput Collector. For better readability, I split the output in several lines and indented some of them. In the actual log, this is just a single line and less readable for humans.
[GC
[PSYoungGen: 142816K->10752K(142848K)] 246648K->243136K(375296K),
, secs
]
[Times: user=, sys=,, real=, secs]
We can recognize a couple of elements from the simple GC log: We have a young generation GC (red) which reduced the occupied heap memory from 246648K to 243136K (blue) and took 0.0935090 seconds. In addition to that, we obtain information about the young generation itself: the collector used (orange) as well as its capacity and occupancy (green). In our example, the “PSYoungGen” collector was able to reduce the occupied young generation heap memory from 142816K to 10752K.
Since we know the young generation capacity, we can easily tell that the GC was triggered because otherwise the young generation would not have been able to accommodate another object allocation: 142816K of the available 142848K were already used. Furthermore, we can conclude that most of the objects removed from the young generation are still alive and must have been moved to the old generation: Comparing the green and blue output shows that even though the young generation was almost completely emptied, the total heap occupancy remained roughly the same.
The “Times” section of the detailed log contains information about the CPU time used by the GC, separated into user space (“user”) and kernel space (“sys”) of the operating system. Also, it shows the real time (“real”) that passed while the GC was running (which, however, with 0.09 is just a rounded value of the 0.0935090 seconds also shown in the log). If, like in our example, the CPU time is considerably higher than the real time passed, we can conclude that the GC was run using multiple threads. In that case, the CPU time logged is the sum of the CPU times of all GC threads. And indeed, I can reveal that the collector used 8 threads in our example.
Now consider the output of a full GC.
[Full GC
[PSYoungGen: 10752K->9707K(142848K)]
[ParOldGen: 232384K->232244K(485888K)] 243136K->241951K(628736K)
[PSPermGen: 3162K->3161K(21504K)],
, secs
]
[Times: user=, sys=,, real=, secs]
In addition to details about the young generation, the log also provides us with details about the old and permanent generations. For all three generations, we can see the collector used, the occupancy before and after GC, and the capacity at the time of GC. Note that each number shown for the total heap (blue) is equal to the sum of the respective numbers of the young and old generations. In our example, 241951K of the total heap are occupied, 9707K of which are in the young generation and 232244K of which belong to the old generation. The full GC took 1.53 seconds, and the CPU time of 10.96 seconds in user space shows that the GC used multiple threads (like above, 8 threads).
The detailed output for the different generations enables us to reason about the GC cause. If, for any generation, the log states that its occupancy before GC was almost equal to its current capacity, it is likely that this generation triggered the GC. However, in the above example, this does not hold for any of the three generations, so what caused GC in this case? With the Throughput Collector, this can actually happen if GC ergonomics (see part 6 of this series) decides that a GC should be run already before one of the generations gets exhausted.
A full GC may also happen when it is explicitly requested, either by the application or via one of the external JVM interfaces. Such a “system GC” can be identified easily in the GC log because in that case the line starts with “Full GC (System)” instead of “Full GC”.
For the Serial Collector, the detailed GC log is very similar to that of the Throughput Collector. The only real difference is that the various sections have different names because other GC algorithms are being used (for example, the old generation section is called “Tenured” instead of “ParOldGen”). It is good that the exact names of the collectors are used because it enables us to conclude just from the log some of the garbage collection settings used by the JVM.
For the CMS Collector, the detailed log for young generation GCs is very similar to that of the Throughput Collector as well, but the same cannot be said for old generation GCs. With the CMS Collector, old generation GCs are run concurrently to the application using different phases. As such, the output itself is different from the output for full GCs. Additionally, the lines for the different phases are usually separated in the log by lines for young generation GCs that happen while the concurrent collection is running. Yet, being familiar with all the elements of GC logging that we have already seen for the other collectors, it is not difficult to understand the logs for the different phases. Only when interpreting durations we should be particularly careful and keep in mind that most of the phases run concurrently to the application. Thus, as opposed to stop-the-world collections, long durations for individual phases (or for a complete GC cycle) do not necessarily indicate a problem.
Ad we know from part 7 of this series, full GCs can still happen when the CMS Collector does not complete a CMS cycle in time. If that happens, the GC log additionally contains a hint as to what caused the full GC, e.g., the well-known “concurrent mode failure”.
In order to keep this article reasonably short, I will refrain from giving a detailed description of the CMS Collector GC log. Also, one of the actual authors of the collector has already published a great explanation here, which I highly recommend for reading.
-XX:+PrintGCTimeStamps and -XX:+PrintGCDateStamps
It is possible to add time and date information to the (simple or detailed) GC log. With -XX:+PrintGCTimeStamps a timestamp reflecting the real time passed in seconds since JVM start is added to every line. An example:
,: [GC 66048K->53077K(251392K), , secs]
,: [GC 119125K->114661K(317440K), , secs]
,: [GC 246757K->243133K(375296K), , secs]
And if we specify -XX:+PrintGCDateStamps each line starts with the absolute date and time when it was written:
--03T12::38.102-: [GC 66048K->53077K(251392K), , secs]
--03T12::38.239-: [GC 119125K->114661K(317440K), , secs]
--03T12::38.513-: [GC 246757K->243133K(375296K), , secs]
It is possible to combine the two flags if both outputs are desired. I would recommend to always specify both flags because the information is highly useful in order to correlate GC log data with data from other sources.
-Xloggc
By default the GC log is written to stdout. With -Xloggc:<file> we may instead specify an output file. Note that this flag implicitly sets -XX:+PrintGC and -XX:+PrintGCTimeStamps as well. Still, I would recommend to set these flags explicitly if desired, in order to safeguard yourself against unexpected changes in new JVM versions.
“Manageable” Flags
A frequently discussed question is whether GC logging should be activated for production system JVMs. The overhead of GC logging is usually rather small, so I have a clear tendency towards “yes”. However, it is good to know that we do not have to decide in favor of (or against) GC logging when starting the JVM.
The HotSpot JVM has a special (but very small) category of flags called “manageable”. For manageable flags, it is possible to change their values at run time. All the flags that we have discussed here and that start with “PrintGC” belong to the “manageable” category. Thus, we can activate or deactivate GC logging for a running JVM whenever and as often as we want. In order to set manageable flags we can, for example, use the jinfo tool shipped with the JDK or use a JMX client and call the setVMOption operation of the HotSpotDiagnostic MXBean.
Ref:
Useful JVM Flags – Part 8 (GC Logging)
Useful JVM Flags – Part 8 (GC Logging)的更多相关文章
- 管中窥豹——从对象的生命周期梳理JVM内存结构、GC调优、类加载、AOP编程及性能监控
如题,本文的宗旨既是透过对象的生命周期,来梳理JVM内存结构及GC相关知识,并辅以AOP及双亲委派机制原理,学习不仅仅是海绵式的吸收学习,还需要自己去分析why,加深对技术的理解和认知,祝大家早日走上 ...
- JVM——垃圾回收(GC)
GC简单介绍 java语言执行在java虚拟机(jvm)上.为了解决有限的空间和性能的保证这个矛盾体,jvm所具备的GC能力.能够有效的清除不用的对象.使空间的利用更加合理.以下介绍该机制的原理. 推 ...
- Spark(八)JVM调优以及GC垃圾收集器
一JVM结构 1 Java内存结构 JVM内存结构主要有三大块:堆内存.方法区和栈. 堆内存是JVM中最大的一块由年轻代和老年代组成,而年轻代内存又被分成三部分,Eden空间.From Survivo ...
- 修改Tomcat的jvm的垃圾回收GC方式为CMS
修改Tomcat的jvm的垃圾回收GC方式 cp $TOMCAT_HOME/bin/catalina.sh $TOMCAT_HOME/bin/catalina.sh.bak_20170815 vi $ ...
- JVM(二)GC
GC简介 Java堆内存 在运行时,java的实例被存放在堆内存区域.当一个对象不在被引用,满足条件就会从堆内存移除并且内存空间被回收.堆内存由三个主要区域 1.新生代 Eden空间(任何实例 ...
- 阿里P8Java大牛仅用46张图让你弄懂JVM的体系结构与GC调优。
本PPT从JVM体系结构概述.GC算法.Hotspot内存管理.Hotspot垃圾回收器.调优和监控工具六大方面进行讲述.图文并茂不生枯燥. 此PPT长达46页,全部展示篇幅过长,本文优先分享前十六页 ...
- JVM相关文章和GC原理算法
参考推荐: Java内存模型及GC原理 一个优秀的Java程序员必须了解的GC机制 Android 智能指针原理(推荐) Java虚拟机规范 Java虚拟机参数 Java内存模型 Java系列教程(推 ...
- 【转】JDK5.0中JVM堆模型、GC垃圾收集详细解析
基本概念 堆/Heap JVM管理的内存叫堆:在32Bit操作系统上有4G的限制,一般来说Windows下为2G,而Linux下为3G:64Bit的就没有这个限制.JVM初始分配的内存由-Xms指定, ...
- JVM内存模型及GC回收算法
该篇博客主要对JVM内存模型以及GC回收算法以自己的理解和认识做以记录. 内存模型 GC垃圾回收 1.内存模型 从上图可以看出,JVM分为 方法区,虚拟机栈,本地方法栈,堆,计数器 5个区域.其中最为 ...
随机推荐
- js加入购物车抛物线动画
天猫将商品加入购物车会有一个抛物线动画,告诉用户操作成功以及购物车的位置,业务中需要用到类似的效果,记录一下实现过程备忘,先上demo 一开始没有想到用抛物线函数去做,也已经忘记还有这么个函数了,想着 ...
- rabbitmq学习(八) —— 可靠机制上的“可靠”
接着上一篇,既然已经有了手动ack.confirm机制.return机制,还不够吗? 以下博文转自https://www.jianshu.com/p/6579e48d18ae和https://my.o ...
- CSS3选择器02—CSS3部分选择器
该部分主要为CSS3新增的选择器 接上一篇 CSS(CSS3)选择器(1) 一.通用兄弟选择器: 24:E ~ F,匹配任何E元素之后的同级F元素. div ~ p{ background-color ...
- Luogu1445 [Violet]樱花 ---- 数论优化
Luogu1445 [Violet]樱花 一句话题意:(本来就是一句话的) 求方程 $\frac{1}{X} + \frac{1}{Y} = \frac{1}{N!}$ 的正整数解的组数,其中$N \ ...
- bzoj1205: [HNOI2005]星际贸易
题目链接 bzoj1205: [HNOI2005]星际贸易 题解 辣鸡题面,毁我青春 辣鸡题面,毁我青 辣鸡题面,毁我 辣鸡题面,毁 第一问,背包dp 第二问 问题转化为在一个序列上经过好多点走到终点 ...
- gdb 调试及优化
调试程序时,在gdb内p var,会提示 No symbol "var" in current context. 即使没有使用任何编译优化选项,仍然不能查看,可能是这些变量被优化到 ...
- 闲话函数式变成与OOP
函数式编程扫盲篇 推薦參考文獻地址:http://byvoid.github.io/slides/apio-fp/index.html 1. 概论 在过去的近十年的时间里,面向对象编程大行其道.以至于 ...
- DELPHI之崩溃地址排错代码查看 转
http://www.cnblogs.com/enli/archive/2009/01/15/1376540.html 最近研究了一下HOOK技术,想抓取某些游戏的包,因此需要注入DLL,结果老是有异 ...
- 在ASP.NET MVC中使用Knockout实践08,使用foreach绑定集合
本篇体验使用 foreach 绑定一个Product集合. 首先使用构造创建一个View Model. var Product = function(data) { this.name = ko.ob ...
- mysql time zone时区的错误解决
错误提示: The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents more than one time zon ...