Skip to content

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 的核心特性:只收集价值最高的 Region

GC 日志的警告信号

警告一: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 FailureEden/老年代分配失败,触发 GC
DefNew / PSYoungGenSerial / Parallel 年轻代收集器
Tenured / ParOldGen老年代收集器
G1 Evacuation PauseG1 年轻代/混合收集
user=real单线程 GC
user > real多线程 GC(user 是所有线程累加)
Collection SetsG1 选中的收集 Region

识别 GC 日志中的警告信号,是诊断 GC 问题的第一步。

下一节,我们来看 日志分析工具(GCEasy/GCViewer)

基于 VitePress 构建