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个区域.其中最为 ...
随机推荐
- 洛谷P2017 [USACO09DEC]晕牛Dizzy Cows [拓扑排序]
题目传送门 晕牛Dizzy Cows 题目背景 Hzwer 神犇最近又征服了一个国家,然后接下来却也遇见了一个难题. 题目描述 The cows have taken to racing each o ...
- MySQL数据库之触发器
1 引言 本文是对MySQL中触发器的总结,从触发器概念出发,结合实例对创建触发器.使用触发器.删除触发器进行介绍. 2 触发器简介 MySQL触发器和存储过程一样,都是嵌入到MySQL的一段程序.触 ...
- JSP的几个页面指令
页面指令:向服务器说明页面自身的特征,以便服务器. 1,<%@page contentType="text/xml;charset=utf-8" %> 客户端---&g ...
- JZYZOJ 2042 多项式逆元 NTT 多项式
http://172.20.6.3/Problem_Show.asp?id=2042 题意:求一个次数界为n的多项式在模P并模x^m的意义下的逆元.P=7*17*2^23+1. 多项式逆元的含义以及求 ...
- hdu 4432 第37届ACM/ICPC天津现场赛B题
题目大意就是找出n的约数,然后把约数在m进制下展开,各个数位的每一位平方求和,然后按m进制输出. 模拟即可 #include<cstdio> #include<iostream> ...
- Markdown基础用法
1. 标题 文字前加#,共6级标题,# 一级标题,## 二级标题,...,###### 六级标题 2. 列表 文字前加-或* 即可变无序列表,文字前加 数字. 即可变有序列表 3. 引用 在引用文本前 ...
- css基础 行内元素 块级元素
1.行内元素(内联元素 inlineElement) 特点:不占据一行,无法设置宽高及行高,其宽度随着内容增加,高度随字体大小而改变,margin只对左右起作用,上下无效. 常见有: a - 锚点,b ...
- 关于tensorflow中tensorborad No dashboards are active for the current data set.的解决办法
说明:这个问题,困惑了好久,在网上查了很久,一直没能解决,直到我在stackoverflow上看到有一位博主的回答 链接在这里:(https://stackoverflow.com/questions ...
- API测试利器postMan 使用教程
自从开始做API开发之后,我就在寻找合适的API测试工具.一开始不是很想用Chrome扩展,用的 WizTools 的工具,后来试过一次 Postman 之后就停不下来了,还买了付费的Jetpacks ...
- 強大的jQuery Chart组件-Highcharts
Highcharts是一个制作图表的纯Javascript类库,主要特性如下: 兼容性:兼容当今所有的浏览器,包括iPhone.IE和火狐等等: 对个人用户完全免费: 纯JS,无BS: 支持大部分的图 ...