MinorGC/FullGC 日志解析
GC 日志解析:看懂 GC 在做什么
GC 日志是 JVM 调优的第一手数据。这一节通过实际日志示例,教你快速读懂 MinorGC 和 FullGC 的日志。
MinorGC 日志解析
JDK 8 MinorGC 日志
bash
2026-03-22T10:00:00.123+0800: [GC (Allocation Failure)
[DefNew: 18432K->2048K(22528K), 0.0156789 secs]
18432K->4096K(3145728K), 0.0157890 secs]
[Times: user=0.10 sys=0.01, real=0.02 secs]逐行解读:
GC (Allocation Failure)
↑ 触发原因:Eden 区分配失败(Eden 满了)
[DefNew: 18432K->2048K(22528K), 0.0156789 secs]
↑ DefNew = Serial 年轻代收集器
↑ 18432K → 2048K:GC 前eden用了18MB,GC 后用了2MB
↑ (22528K):年轻代总大小(Eden + Survivor)
↑ 0.0156789 secs:MinorGC 停顿时间
18432K->4096K(3145728K), 0.0157890 secs
↑ 整个堆从18MB → 4MB,年轻代总大小3GB
↑ 注意:这里显示的是整个堆的情况
[Times: user=0.10 sys=0.01, real=0.02 secs]
↑ user=0.10s:GC 线程消耗的总 CPU 时间
↑ sys=0.01s:系统调用消耗的时间
↑ real=0.02s:实际墙钟时间
↑ user > real:多线程 GC(user 时间是所有 GC 线程累加)Parallel GC MinorGC 日志(JDK 8 Throughput)
bash
2026-03-22T10:00:00.456+0800: [GC
[PSYoungGen: 1024000K->204800K(1187840K)]
1024000K->204800K(2097152K), 0.0456789 secs]
[Times: user=0.18 sys=0.01, real=0.05 secs]解读:
[PSYoungGen: 1024000K->204800K(1187840K)]
↑ PSYoungGen = Parallel Scavenge 年轻代收集器
↑ 年轻代从 1000MB → 200MB(总年轻代 1152MB)
1024000K->204800K(2097152K)
↑ 堆从 1000MB → 200MB(总堆 2048MB = 2GB)
user=0.18, real=0.05
↑ 约 3.6 倍关系 → 大约 4 个 GC 线程G1 MinorGC 日志(JDK 9+)
bash
2026-03-22T10:00:00.789+0800: [GC pause (G1 Evacuation Pause) (young)
Using 8 workers
, 0.0123456 secs]
[Eden: 1536.0M(1536.0M)->0.0B
Survivors: 96.0M->128.0M
Heap: 4096.0M(4096.0M)->2048.0M(4096.0M)]解读:
GC pause (G1 Evacuation Pause) (young)
↑ G1 年轻代收集
↑ Evacuation Pause = 复制/转移暂停
Using 8 workers
↑ 8 个 GC 工作线程并行执行
[Eden: 1536.0M(1536.0M)->0.0B]
↑ Eden 从 1536MB 用满 → 0MB(清空了)
Survivors: 96.0M->128.0M
↑ Survivor 从 96MB → 128MB(部分对象晋升 Survivor)
Heap: 4096.0M(4096.0M)->2048.0M(4096.0M)
↑ 堆从 4GB 使用 → 2GB 使用(总堆 4GB,不变)FullGC 日志解析
Serial GC FullGC 日志(JDK 8)
bash
2026-03-22T10:05:30.123+0800: [Full GC (Allocation Failure)
[DefNew: 18432K->18432K(22528K), 0.0012345 secs]
[Tenured: 2621440K->1835008K(3145728K), 1.2345678 secs]
[PSYoungGen: 18432K->0K(22528K), 0.0012345 secs]
[ParOldGen: 2621440K->1835008K(3145728K), 1.2345678 secs]
2764800K->1835008K(3145728K), 1.2358023 secs]
[Times: user=1.24 sys=0.01, real=1.24 secs]解读:
Full GC (Allocation Failure)
↑ 触发原因:分配失败(老年代满)
[Tenured: 2621440K->1835008K(3145728K), 1.2345678 secs]
↑ 老年代(Tenured)从 2560MB → 1792MB
↑ 老年代总大小 3072MB
↑ 停顿了 1.23 秒!
Total: 2764800K->1835008K(3145728K)
↑ 整个堆:2.7GB → 1.8GB(2GB堆)
↑ 注意:FullGC 后堆仍然占用了 1.8GB
→ 说明有很多对象无法回收(正常现象)CMS FullGC 日志(JDK 8)
bash
# 初始标记
2026-03-22T10:00:00.000: [GC (CMS Initial Mark)
[CMS: 1048576K->1048576K(2097152K), 0.0123456 secs]
[Times: user=0.01 sys=0.00, real=0.01 secs]
# 重新标记
2026-03-22T10:00:00.456: [GC (CMS Final Remark)
[CMS: 1089536K->1098765K(2097152K), 0.0234567 secs]
[Times: user=0.03 sys=0.01, real=0.02 secs]
# 清理
2026-03-22T10:00:01.000: [GC (CMS Final Sweep)
[CMS: 1098765K->1098765K(2097152K), 0.0056789 secs]G1 MixedGC 日志(JDK 9+)
bash
2026-03-22T10:00:30.000: [GC pause (G1 Evacuation Pause) (young)
Using 8 workers
, 0.0156789 secs]
[Eden: 0.0B(0.0B)->0.0B
Survivors: 256.0M->128.0M
Heap: 4096.0M(4096.0M)->2048.0M(4096.0M)]
2026-03-22T10:00:31.000: [GC pause (G1 Evacuation Pause) (mixed)
Using 8 workers
, 0.0456789 secs]
[Eden: 0.0B(0.0B)->0.0B
Survivors: 128.0M->256.0M
Heap: 4096.0M(4096.0M)->2560.0M(4096.0M)]
[Collection Sets: 512.0M selected]解读:
(mixed) vs (young)
↑ (mixed) = 混合收集,同时回收年轻代和老年代
↑ (young) = 仅年轻代收集
[Collection Sets: 512.0M selected]
↑ 选中了 512MB 的老年代 Region 进行收集
↑ 这是 G1 的核心特性:只收集价值最高的 RegionGC 日志的警告信号
警告一:FullGC 频繁
[Full GC (Allocation Failure)
[Tenured: 1000M->980M(2000M), 2.345 secs]
[Full GC 频繁 - 每次都清理不掉大量对象]诊断:可能存在内存泄漏或大对象。
警告二:GC 后内存不降
[Full GC (Allocation Failure)
Tenured: 1900M->1800M(2000M)
[每次 FullGC 后,Tenured 仍然在 90% 左右]诊断:内存泄漏,对象无法回收。
警告三:GC 时间过长
[Full GC (Allocation Failure)
Tenured: ... 5.678 secs]
[Times: user=5.6 sys=0.1, real=5.7 secs]
[GC 停顿了 5.7 秒,对在线服务是致命的]诊断:Serial Old 在整理大量对象,需要切换到 G1 或 ZGC。
警告四:对象晋升太快
[GC (Allocation Failure)
[ParNew: 200MB->200MB(220MB), 0.050 secs]
[Survivor 空间不足,对象被强制晋升老年代]诊断:Survivor 区太小,需要增大 SurvivorRatio 或年轻代大小。
jstat 辅助分析
GC 日志之外,jstat 提供实时监控:
bash
# 每秒输出一次 GC 统计
jstat -gcutil <pid> 1000
# 输出:
# S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
# 0.00 0.00 65.21 78.33 92.00 88.00 123 2.34 5 12.34 0 14.68
# ↑
# S0/S1/E/O:各区使用率百分比
# YGC:年轻代 GC 次数
# FGCT:Full GC 总时间本节小结
GC 日志核心指标解读:
| 日志字段 | 含义 |
|---|---|
Allocation Failure | Eden/老年代分配失败,触发 GC |
DefNew / PSYoungGen | Serial / Parallel 年轻代收集器 |
Tenured / ParOldGen | 老年代收集器 |
G1 Evacuation Pause | G1 年轻代/混合收集 |
user=real | 单线程 GC |
user > real | 多线程 GC(user 是所有线程累加) |
Collection Sets | G1 选中的收集 Region |
识别 GC 日志中的警告信号,是诊断 GC 问题的第一步。
下一节,我们来看 日志分析工具(GCEasy/GCViewer)。
