GC日志是JVM内存行为的精确快照,需重点解读时间戳(绝对时间与启动后秒数)、耗时(real为业务卡顿时长)、GC类型与触发原因(如Allocation Failure或Metadata GC Threshold)、内存区域变化(如PSYoungGen: A→B(C))及收集器特有阶段标识(如G1 Evacuation Pause)。

GC日志不是一串乱码,而是JVM内存行为的精确快照。每个字段都对应一次真实发生的回收动作,关键在于看懂它在说什么、哪里异常、为什么发生。
时间戳与运行时长
日志开头的时间信息包含两层含义:系统绝对时间(如 2024-07-15T10:20:30.123+0800)和JVM启动后经过的秒数(如 123.456)。前者便于关联其他监控系统(如APM、日志平台),后者用于判断GC是否随应用运行时间推移而越来越频繁。
耗时部分形如 0.0234567 secs,代表本次GC实际暂停应用的时间(Stop-The-World),即real time;[Times: user=0.01 sys=0.01, real=0.02 secs] 中的user/sys反映JVM线程在CPU上消耗的时间,real才是业务感知到的卡顿长度。若real远大于user+sys,可能说明系统资源争抢严重(如IO阻塞、CPU调度延迟)。
GC类型与触发原因
方括号中紧跟的标识直接说明回收性质:
- GC 或 [GC (Allocation Failure)]:典型Minor GC,多由Eden区无法分配新对象引发;
- Full GC 或 [Full GC (System.gc())]:全堆回收,常见于老年代空间不足、Metaspace耗尽、显式调用System.gc()或CMS失败后退化;
- [GC (Metadata GC Threshold)]:元空间触发回收,提示类加载过多或未及时卸载;
- [GC (Last ditch collection)]:JVM已尝试多种方式仍无法腾出足够空间,即将OOM。
触发原因比GC类型更重要——它指出问题根源:是对象分配太快? Survivor区过小导致提前晋升?还是老年代真的撑不住了?
内存区域变化数据
核心字段如 [PSYoungGen: 8192K->1024K(9216K)] 102400K->32768K(349568K) 需拆解理解:
- PSYoungGen: A->B(C):年轻代使用量从A降到B,总容量为C。若B持续接近C(如8000K->7900K),说明存活对象多、晋升压力大;
- 整体堆:X->Y(Z):整个堆使用量从X降到Y,总大小Z。若Y长期高于Z的70%,尤其老年代占比持续上升,预示内存泄漏或分配策略不合理;
- 不同收集器写法略有差异:ParNew日志标ParNew,G1日志会出现G1 Evacuation Pause,CMS日志则分上下两段分别描述年轻代和老年代回收结果。
收集器特有阶段与标记
不同垃圾回收器会在日志中暴露内部阶段,这是深度诊断的关键:
- CMS 日志中可见 concurrent mode failure(并发模式失败),意味着CMS来不及完成回收,被迫退化为Serial Old Full GC;
- G1 日志会区分 YGC(仅年轻代)、Mixed GC(年轻代+部分老年代)、Full GC(退化场景),并附带 [GC pause (G1 Evacuation Pause) (young)] 等明确阶段标识;
- ZGC/Shenandoah 日志强调 Pause 时间极短(通常Load barrier、Relocate 等并发阶段耗时,用于验证是否真正达成低延迟目标。
这些细节不单是名词,它们对应着真实的执行路径。比如看到多次Mixed GC但老年代仍在缓慢增长,大概率说明G1的并发周期没跟上对象晋升速度,需调大堆或调整-XX:G1HeapWastePercent等参数。

















