识别回收类型→定位内存区域变化→关联触发原因:日志中“GC (Allocation Failure)”表示Minor GC,新生代Eden满触发;“PSYoungGen: A→B(C)”反映新生代回收前后占用及容量;老年代增长或Survivor阈值过低(如new threshold 2)则提示晋升异常或内存泄漏。

看懂经典垃圾回收器(如 Serial、Parallel、CMS)在老版本 JVM(JDK 7/8)下打印的“分代收集黄金日志”,关键不是背格式,而是建立三步解码习惯:**识别回收类型 → 定位内存区域变化 → 关联触发原因**。这类日志虽不带 G1/ZGC 的 Region 信息,但结构清晰、字段稳定,反而更利于快速定位瓶颈。
认准日志开头的 GC 类型标识
经典分代日志第一眼就告诉你“谁动了哪块内存”:
-
GC:仅新生代回收(Young GC / Minor GC),比如
[GC (Allocation Failure) ...]或[PSYoungGen: 1234K->567K(8192K)] ... -
Full GC:跨代回收,含新生代 + 老年代 + 元空间(JDK 8+)或永久代(JDK 7),如
[Full GC (Metadata GC Threshold) ...] - 注意括号里的原因:
Allocation Failure表示 Eden 区满;Metadata GC Threshold是元空间快满;Concurrent Mode Failure是 CMS 回收失败退化为 Serial Old —— 这类词直接指向根因。
拆解堆空间变化的三段式结构
典型详细日志形如:
[GC (Allocation Failure) [PSYoungGen: 70640K->10116K(141312K)] 80541K->20017K(227328K), 0.0172573 secs]它其实包含三层含义:
-
PSYoungGen 部分:新生代内部变化 →
70640K->10116K(141312K)表示 Young GC 前 Eden+S0/S1 占用 70640K,GC 后只剩 10116K 存活对象,新生代总容量 141312K(即 -Xmn 设置值) -
整体堆部分:全堆视角 →
80541K->20017K(227328K)GC 前整个堆已用 80541K,GC 后降到 20017K,堆总大小 227328K(即 -Xmx 值) -
耗时与线程时间:
0.0172573 secs是实际暂停时间(real time),后面[Times:user=0.03 sys=0.00,real=0.02]可判断是否受 CPU 资源争抢影响
重点关注老年代与晋升行为线索
频繁 Full GC 或老年代增长过快,往往藏在 Young GC 日志的细节里:
- 看
ParOldGen或Tenured Generation字段是否出现在某次 GC 中 —— 如果某次 Young GC 后紧跟老年代使用量上升(如[ParOldGen: 12000K->12500K(62464K)]),说明有对象提前晋升 - 留意
Desired survivor size和new threshold行(需加-XX:+PrintTenuringDistribution): 若日志中反复出现new threshold 2 (max 15),代表 Survivor 区装不下,大量对象仅经历 2 次 GC 就进老年代,这是典型的“晋升风暴”,常由 SurvivorRatio 设置不当或对象生命周期异常引起 - 对比连续几次 Young GC 后老年代占用增幅:若每次 GC 后老年代都+5MB,而新生代回收效果良好,大概率是缓存未清理、监听器未注销等隐性内存泄漏
对照参数还原运行时内存布局
日志本身不带配置,但能反推关键参数是否合理:
- 从
PSYoungGen: xxxK->yyyK(zzzzK)的 zzzzK 值,可确认 -Xmn 设置;从整体堆容量反推 -Xmx;两者比值就是-XX:NewRatio - 若日志中 Eden 区长期 >95% 使用率,而 Survivor 区几乎为空(如
from space 1024K, 0% used),说明对象“秒杀即死”,但新生代可能偏小或分配速率过高 - 发现
Metaspace使用量持续上涨且接近上限(如Metaspace: 20599K->20599K(1067008K)),要检查是否动态生成类(如 CGLIB、JSON 反序列化)、未释放 ClassLoader


















