JVM 看懂GC日志
1. 理解GC日志
阅读GC日志是处理Java
虚拟机问题的基础技能,它只是一些人为确定的规则,没有太多技术含量。每种收集器的日志形式都是由塔门自身的实现决定的,换言之,每种收集器的日志格式可能都不同,但虚拟机设计者为方便用户阅读,将各个收集器的日志都维持一定的共性,例如以下经典GC日志。
- 怎么查看GC日志,在
Idea
的Application
设置中添加VM options
参数-XX:+PrintGCDetails
。
// VM options = -XX:+PrintGCDetails
public class GCTest {
public static void main(String[] args) throws InterruptedException {
System.gc();
}
}
//输出
[GC (System.gc()) [PSYoungGen: 5243K->791K(76288K)] 5243K->799K(251392K), 0.0013710 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
[Full GC (System.gc()) [PSYoungGen: 791K->0K(76288K)] [ParOldGen: 8K->672K(175104K)] 799K->672K(251392K), [Metaspace: 2958K->2958K(1056768K)], 0.0065557 secs] [Times: user=0.03 sys=0.01, real=0.00 secs]
[GC
和[Full GC
说明了这次垃圾回收的停顿类型,而不是用来区分新生代或者是老年代的GC。如果有Full
,说明这次GC是发生了 Stop-The-World。接下来的[PSYoungGen
表示GC发生的区域,这里显示的区域名称和所使用的GC收集器相关,比如Serial
收集器新生代名字就叫DefNew
,ParNew
收集器,新生代名是ParNew
,Parallel Scavenge
收集器,新生代名字为PSYoungGen
,我默认用的是Parallel Scavenge
收集器,老年代和新生代同理,名称也是由收集器决定的。后面括号5243K->791K(76288K)
表示年轻代GC前容量->年轻代GC后容量(年轻代总容量),而括号后的5243K->799K(251392K)
表示Java堆GC前容量->Java堆GC后容量(Java堆总容量),再往后0.0013710 secs
表示GC花费时间,单位秒。有的收集器会给出更准确时间比如[Times: user=0.01 sys=0.00, real=0.00 secs]
,user、sys、real与Linux 的 Time 命令所输出的时间含义一致,分别代表用户态消耗的CUP时间,内核态消耗CPU时间和操作从开始到结束所经过的墙钟时间(Wall Clock TIme)。墙钟时间包含各种非运算等待时间,例如磁盘I/O,等待线程阻塞等,而CPU时间不包括这些,但当多CUP或者多核的话,多线程操作会叠加这些时间,所以 user 或者 sys 超过 real 时间是正常的。
- 下表为
VM options
参数
参数 | 描述 |
UseSerialGC | 虚拟机运行在 Client 模式下的默认值,打开此开关后,使用Serial + Serial Old 收集器组合进行内存回收 |
UseParNewGC | 打开此开关后,使用 ParNew + Serial Old 收集器组合进行内存回收(64位服务器被启用警告,未来版本可能删除) |
UseConcMarkSweepGC | 打开此开关后,使用 ParNew + CMS + SerialOld 的收集器组合进行内存回收。Serial Old 收集器将作为 CMS 收集器出现 Concurrent Mode Failure 失败后的后备收集器使用 |
UseParallelGC | 虚拟机运行在Server 模式下的默认值,打开此开关后,使用 Parallel Scavenge + Serial Old (PS MarkSweep) 的收集器组合进行垃圾手机 |
UseParallelOldGC | 打开此开关后,使用 Parallel Scavenge + Parallel Old 的收集器组合进行垃圾回收 |
SurvivorRatio | 新生代中的 Eden 区域与Survivor 区域容量比值,默认为8,代表 Eden:Survivor = 8:1 |
PretenureSizeThreshold | 直接晋升到老年代的对象大小,设置这个参数后,大于这个参数的对象将直接在老年代分配 |
MaxTenuringThreshold | 晋升到老年代的对象年龄,每个对象在坚持一次 Minor GC (年轻代GC)后,年轻就增加 1,当超过这个值则进入老年代 |
HandlePromotionFailure | 是否允许分配担保失败,即老年代的剩余空间不足以应付新生代的整个Eden 和 Survivor 区所有对象都存活的极端情况 |
ParallelGCThreads | 设置并行GC时进行内存回收的线程数 |
GCTimeRatio | GC时间占总时间的比率,默认值99,即允许1%的GC时间,仅在使用PS收集器时生效 |
MaxGCPauseMillis | 设置GC最大停顿时间,仅在使用PS收集器生效 |
CMSInitiatingOccupancyFraction | 设置CMS收集器在老年代空间被使用多少后触发垃圾收集,默认值为68%,仅在使用CMS收集器时生效 |
UseCMSCompactAtFullCollection | 设置CMS收集器在完成垃圾收集后是否要进行一次内存碎片整理,仅在使用CMS收集器时生效 |
CMSFullGCsBeforeCompaction | 设置CMS收集器在进行若干次垃圾收集后再启动一次内存碎片整理。仅在使用CMS收集器时生效 |