#GC 日志解读与分析
GC 日志是排查 GC 问题的第一手资料。学会解读 GC 日志,是进行 GC 调优的基础。
本文将详细介绍 GC 日志的格式、含义以及如何分析常见问题。
#GC 日志配置
#基本配置
# 开启详细 GC 日志
java -Xms4g -Xmx4g \
-Xlog:gc*:file=gc.log:time,uptime,level,tags:filecount=5,filesize=10M \
-jar application.jar#配置参数说明
| 参数 | 说明 |
|---|---|
gc* | 日志标签,匹配所有 gc 相关日志 |
file=gc.log | 输出到文件 |
time | 包含时间戳 |
uptime | 包含 JVM 运行时间 |
level | 包含日志级别 |
tags | 包含标签信息 |
filecount=5 | 保留 5 个文件 |
filesize=10M | 每个文件最大 10MB |
#Serial/Parallel 日志格式
#Young GC 日志
// Serial/Parallel Young GC 日志
2024-01-15T10:30:45.123+0800: 12345.678: [GC (Allocation Failure)
Desired survivor size 524288 bytes, new threshold 1 (max 15)
- age 1: 1048576 bytes, 1048576 bytes total
- age 2: 524288 bytes, 1572864 bytes total
, 0.0123456 secs]#Full GC 日志
// Serial Full GC 日志
2024-01-15T10:30:50.123+0800: 12350.678: [Full GC (Allocation Failure)
[PSYoungGen: 512K->0K(1536K)]
[ParOldGen: 2048K->1872K(4096K)]
2560K->1872K(5632K),
[Metaspace: 256K->256K(1024K)],
0.0234567 secs]
[Times: user=0.05 sys=0.01, real=0.02 secs]#字段说明
| 字段 | 说明 |
|---|---|
[GC | Young GC |
[Full GC | Full GC |
(Allocation Failure) | GC 触发原因 |
PSYoungGen | Parallel Scavenge 新生代 |
ParOldGen | Parallel Old 老年代 |
[Times: user=0.05 sys=0.01, real=0.02] | CPU 时间/系统调用时间/实际时间 |
#G1 日志格式
#Young GC 日志
// G1 Young GC 日志
2024-01-15T10:30:45.123+0800: [GC pause (G1 Evacuation Pause) (young), 0.0451234 secs]
[Eden: 2048.0M(2048.0M)->0.0B(2048.0M)]
[Survivor: 256.0M(256.0M)->256.0M(256.0M)]
[Old: 4096.0M->4096.0M(6144.0M)]
[Humongous: 0.0B->0.0B]
[Metaspace: 128.5M->128.5M(256.0M)]
[Heap: 8192.0M->8192.0M(8192.0M)]
[GCCause: G1 Evacuation Pause]
[Times: user=0.15 sys=0.02, real=0.05 secs]#Mixed GC 日志
// G1 Mixed GC 日志
2024-01-15T10:31:00.123+0800: [GC pause (G1 Evacuation Pause) (mixed), 0.1851234 secs]
[Eden: 1024.0M(2048.0M)->0.0B(2048.0M)]
[Survivor: 256.0M(256.0M)->256.0M(256.0M)]
[Old: 2048.0M->1024.0M(4096.0M)]
[Humongous: 0.0B->0.0B]
[Metaspace: 128.5M->128.5M(256.0M)]
[Heap: 8192.0M->8192.0M(8192.0M)]
[GCCause: G1 Humongous Allocation]#字段说明
| 字段 | 说明 |
|---|---|
G1 Evacuation Pause | G1 的转移暂停 |
(young) / (mixed) | GC 类型 |
Eden: X->Y(Z) | Eden 区:使用前->使用后(总量) |
Survivor: X->Y(Z) | Survivor 区:使用前->使用后(总量) |
Old: X->Y(Z) | 老年代:使用前->使用后(总量) |
GCCause | GC 触发原因 |
#ZGC 日志格式
#基本日志
// ZGC 日志
[2024-01-15T10:30:45.123+0800] GC(12345) Garbage Collection Phase: Mark
[2024-01-15T10:30:45.145+0800] GC(12345) Duration: 12.345ms
[2024-01-15T10:30:45.145+0800] GC(12345) Heap: 65536M->32768M(65536M)
[2024-01-15T10:30:45.145+0800] GC(12345) Metaspace: 128M->128M(256M)
[2024-01-15T10:30:45.145+0800] GC(12345) ZHeap: 32768M->16384M(65536M)#详细阶段日志
// ZGC 详细日志
[2024-01-15T10:30:45.123+0800] GC(12345) Garbage Collection Phase: Mark
[2024-01-15T10:30:45.130+0800] GC(12345) Runtime Weak Root Processing: 5.123ms
[2024-01-15T10:30:45.135+0800] GC(12345) Concurrent Mark: 4.567ms
[2024-01-15T10:30:45.140+0800] GC(12345) Non-Zero Tail Marking: 0.123ms
[2024-01-15T10:30:45.145+0800] GC(12345) Duration: 12.345ms#字段说明
| 字段 | 说明 |
|---|---|
Garbage Collection Phase | 当前 GC 阶段 |
Duration | 阶段耗时 |
Heap: X->Y(Z) | 堆内存:使用前->使用后(总量) |
ZHeap | ZGC 管理的堆内存(不含元空间) |
#GC 日志分析方法
#使用命令行分析
# 统计 GC 次数
grep -c "Full GC" gc.log
# 统计 Young GC 次数
grep -c "GC (Allocation Failure)" gc.log
# 提取停顿时间
grep "real=" gc.log | awk -F'real=' '{print $2}' | awk '{sum+=$1; count++} END {print "平均停顿:", sum/count "ms, 总次数:", count}'#使用工具分析
| 工具 | 说明 |
|---|---|
| GCViewer | 图形化 GC 日志分析工具 |
| GCEasy | 在线 GC 日志分析平台 |
| GCPlot | 开源 GC 日志分析工具 |
#常见问题模式
#问题一:GC 过于频繁
// 症状:GC 次数过多
[GC] [Times: user=0.01 sys=0.00, real=0.01 secs] // 间隔很短
[GC] [Times: user=0.01 sys=0.00, real=0.01 secs]
[GC] [Times: user=0.01 sys=0.00, real=0.01 secs]分析:
- 新生代太小
- 对象分配速率过高
- 需要增加堆内存或调整新生代比例
#问题二:Full GC 频繁
// 症状:Full GC 频繁
[Full GC] [Times: user=0.10 sys=0.01, real=0.10 secs]
[Full GC] [Times: user=0.10 sys=0.01, real=0.10 secs]分析:
- 老年代空间不足
- 内存泄漏
- 对象晋升年龄过小
#问题三:停顿时间过长
// 症状:停顿时间超过目标
[GC pause (G1 Evacuation Pause) (young), 0.5001234 secs] // 超过 200ms 目标分析:
- 新生代太大
- GC 线程数不足
- 需要切换到 ZGC 等低延迟收集器
#日志分析实战
#使用 GCEasy
GCEasy(https://gceasy.io)是在线 GC 日志分析工具,支持:
- 上传 GC 日志文件
- 自动分析 GC 事件
- 生成可视化图表
- 提供优化建议
#使用 jstat 分析
# 查看 GC 统计信息
jstat -gcutil -t <pid> 1000
# 输出
Timestamp S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT CGC CGCT GCT
12345.0 0.0 0.0 0.0 0.0 2048.0 1024.0 65536.0 32768.0 131072.0 118000.0 16384.0 14000.0 123 12.345 0 0.000 5 5.678 18.023#字段说明
| 字段 | 说明 |
|---|---|
S0C/S1C | Survivor 0/1 容量 |
S0U/S1U | Survivor 0/1 使用量 |
EC/EU | Eden 容量/使用量 |
OC/OU | 老年代容量/使用量 |
MC/MU | 元空间容量/使用量 |
YGC/YGCT | Young GC 次数/总时间 |
FGC/FGCT | Full GC 次数/总时间 |
GCT | 总 GC 时间 |