垃圾收集器很大程度上会影响应用的吞吐量和延迟。在调优之前,首先要监控,继而进行分析。那我们先看一下如何获取GC数据,并理解这些数据。
获取GC数据
可以在命令行中指定下面一种选项:
- -verbose:gc或-verbosegc
- -XX:+PrintGCDetails——获取的信息比-verbose:gc更多
如果要获取GC执行的时间,计算GC的持续时间和频率,可以在命令行中指定任一选项:
- -XX:+PrintGCTimeStamps——显示从JVM启动到执行GC时流逝的时间,单位是秒
- -XX:+PrintGCDateStamps——显示执行GC时的本地时间(Java 6 update 4才开始支持)
要想观察GC的开销,或者看应用的延迟是应用本身的延迟,还是JVM GC的stop-the-world阶段的开销,可以指定-XX:+PrintGCApplicationConcurrentTime和-XX:+PrintGCApplicationStoppedTime选项。
另外还可以使用-Xloggc:<fileName>选项将GC数据直接输出到文件中,以便进行离线分析。
输出示例
常规输出
下面是Java 7 update 71(不同版本的输出可能会略有不同)上使用-XX:+PrintGCDetails获取的输出示例:
22.435: [Full GC [PSYoungGen: 638K->0K(36352K)] [ParOldGen: 8507K->9082K(44032K)] 9146K->9082K(80384K) [PSPermGen: 14392K->14392K(21504K)], 0.0547773 secs] [Times: user=0.08 sys=0.00, real=0.06 secs]
第一条信息:
GC说明是minor GC(年轻代GC)。
PSYoungGen表示收集使用的收集器是多线程垃圾收集器Parallel Scavenge。
1151K->638K(36352K)中,1151K表示收集前年轻代占用的内存,638K表示收集后年轻代占用的内存。由于年轻代分为Eden和两个Suvivor,minor收集后Eden为空,所以该值也是Survivor的占用量。括号中的36352K是年轻代的大小。
9659K->9146K(80384K)中,9659K表示收集前整个堆占用的内存,9146K表示收集后整个堆占用的内存。括号里的80384K是Java堆的总量,可以算出老年代的大小是44032K(80384K-36352K)。
0.0032716是整次GC的暂停时间。
[Times: user=0.03 sys=0.00, real=0.00 secs]里,user是垃圾收集器执行非操作系统调用指令所耗费的CPU时间,sys是垃圾收集器执行操作系统调用所耗费的CPU时间, real表示完成GC的实际时间。
GC之后,年轻代减少了513K(1151K-638K),老年代占用的空间则没有变化((9146K-638K)-(9659K-1151K)),这说明年轻代里的对象都被回收了,没有晋升到老年代中。
第二条信息:
Full GC说明是full GC,是对整个堆进行GC,包括年轻代、老年代和永久代。
PSYoungGen: 638K->0K(36352K)的含义和第一条信息里的PSYoungGen: 1151K->638K(36352K)一样。
ParOldGen: 8507K->9082K(44032K)表示老年代收集使用的是多线程垃圾收集器Parallel Old,收集前老年代占用8507K,收集后占用9082K,老年代的大小是44032K。
PSPermGen: 14392K->14392K(21504K)说明GC前永久代的占用量是14392K,GC后永久代的占用量是14392K,而永久代的大小是21504K。
带延迟信息的输出
下面是Java 7 update 71上使用-XX:+PrintGCDetails和-XX:+PrintGCApplicationConcurrentTime、-XX:+PrintGCApplicationStoppedTime选项获取的输出示例:
21.719: [GC [PSYoungGen: 1815K->64K(15360K)] 10319K->8567K(49664K), 0.0035923 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
21.723: [Full GC [PSYoungGen: 64K->0K(15360K)] [ParOldGen: 8503K->8523K(34304K)] 8567K->8523K(49664K) [PSPermGen: 14392K->14392K(22016K)], 0.0500793 secs] [Times: user=0.12 sys=0.00, real=0.05 secs]
21.773: Total time for which application threads were stopped: 0.0542506 seconds
在这个片段中,应用运行了1.83秒,GC用了0.054秒,此次GC大约有3%的开销。
显式GC
如果GC输出信息中包含(System),那说明这次GC是应用显式调用System.gc()所引起的。Java通常不建议应用进行显式的垃圾收集,要是在GC输出中发现该信息,就需要调查代码显式GC的原因了。
[Full GC (System) [PSYoungGen: ......
小结
通常来说,如果minor GC时,年轻代里的对象大部分被晋升到了老年代,被GC的并不多,那可以说明年轻代太小了。但在minor GC前后,老年代的大小要是没有发生变化,那意味着没有对象从年轻代提升到老年代。这是个好现象,说明minor GC回收了较多的垃圾对象,可以减少full GC的频率(full GC的持续时间很长)。
如果日志里只有full GC,每次full GC后,老年代几乎没回收什么空间,而且年轻代总有很大的占用量,那很可能是老年代空间不够大。
GC调优就基于对数据的分析,以及应用追求的性能指标(吞吐量、延迟、抑或内存占用),然后调整相应的设置,再进行新一轮的“监控——分析——调优”,……,直到满足应用的性能指标。
相关推荐
资源名称:深入理解JVM & G1 GC内容简介:G1 GC提出了不确定性Region,每个空闲Region不是为某个固定年代准备的,它是灵活的,需求驱动的,所以G1 GC代表了先进性。《深入理解JVM & G1 GC》主要为学习Java语言的...
深入理解JVM &G1; GC内部结构,年轻代,老年代,元空间等分布情况
G1 GC提出了不确定性Region,每个空闲Region不是为某个固定年代准备的,它是灵活的,需求驱动的,所以G1 GC代表了先进性。本书主要为学习Java语言的学生、初级程序员提供GC的使用参考建议及经验,着重介绍了G1 GC ...
深入jvm垃圾回收 调优细节。
gcviewer是一个可视化详细gc输出的小工具。
最新的G1学习资料,JVM&g1gc;带书签,完整版本,好书。
GC0329是国内最大的cmos图像传感器厂商格科微电子最新推出的一款VGA sensor
几何公差 GDT GG-GC-GX-GN的正确理解
同时,为了能更深入理解与之相关的知识点,本文特地编写了“第二章 基础知识”,详细的讲解与GC学习相关的JVM架构、JVM选项、Object内存布局、指针压缩等内容,以便读者能更加清晰的理解GC原理的底层逻辑。
STM32C8T6单片机,液晶驱动芯片是GC9106,1.77寸液晶。背光PWM输出,可以正常显示,可以直接显示图片
JVM 输出 GC 日志导致 JVM 卡住
GC9307是一个262,144色的单芯片SoC驱动器,用于TFT液晶显示器,分辨率为240rgbx320点,包括720通道源驱动,320通道栅极驱动,172800字节的图形显示240rgbx320点的数据和电源电路。 GC9307支持并行8-/9-/16-/18位...
首先:谈谈托管,什么叫托管,我的理解就是托付C#运行环境帮我们去管理,在这个运行环境中可以帮助我们开辟内存和释放内存,开辟内存一般用new,内存是随机分配的,释放主要靠的是GC也就是垃圾回收机制。哪么有两个...
gc4023 datasheet
SENSOR_GC1054的寄存器配置以及基本图像配置
JVM、GC详解及调优,JVM、GC详解及调优,JVM、GC详解及调优
《G1 GC 性能优化实战.pdf》
GC0308 MTK平台驱动,具体见附件, camera_sensor_GC0308.c camera_sensor_GC0308.h camera_info_GC0308.c camera_info_GC0308.h
JVM内存管理的介绍,编写GC友好的代码。 本材料主要关心 Sun Hotspot JVM 6的内存管理 Sun Hotspot JVM 6的GC模型 主要针对JVM6的GC模型,但也会简单介绍Java 7的G1 编写GC友好代码的一些技巧