开启-XX:+PrintGCDetails和-XX:+PrintGCDateStamps是分析Java GC行为最基础有效的手段,前者输出堆区变化、耗时等详情,后者添加绝对时间戳便于业务关联;不同收集器(如PS、CMS、G1、ZGC)日志结构与关键词差异显著,需据此识别类型并结合频率、内存趋势、real/user/sys时间差等指标判断健康状况。

Java中开启 -XX:+PrintGCDetails 和 -XX:+PrintGCDateStamps 是分析GC行为最基础也最有效的手段。日志本身不难读,关键在于理解不同垃圾收集器(如Serial、Parallel、CMS、G1、ZGC、Shenandoah)输出结构的差异和核心字段含义。
日志时间戳与基本格式怎么看
-XX:+PrintGCDateStamps 会在每条GC日志前加上绝对时间(如 2024-05-20T14:22:36.123+0800),便于关联业务时间点;-XX:+PrintGCDetails 则展开详细信息,包括堆各区域大小变化、回收耗时、晋升情况等。
典型开头格式为:
2024-05-20T14:22:36.123+0800: [GC (Allocation Failure) [PSYoungGen: 123456K->12345K(234567K)] 345678K->234567K(789012K), 0.0456789 secs] [Times: user=0.12 sys=0.01, real=0.05 secs]- Allocation Failure 表示触发原因是年轻代空间不足(其他常见原因还有 Metadata GC Threshold、GCLocker Initiated GC、System.gc() 等)
- PSYoungGen 说明使用的是 Parallel Scavenge 收集器(“PS”即 Parallel Scavenge);若看到 G1 Evacuation Pause 或 ZGC Pause,则对应 G1 或 ZGC
- 123456K->12345K(234567K) 表示年轻代使用量从 123456K 降到 12345K,总容量 234567K
- 345678K->234567K(789012K) 是整个堆的变化:回收前总占用 345678K → 回收后 234567K,堆最大容量 789012K
- real=0.05 secs 是实际耗时(墙钟时间),user/sys 是CPU时间,三者差异大可能意味着GC期间发生停顿或I/O等待
不同收集器日志的关键识别特征
同一参数组合下,各收集器日志结构和术语差异明显,看日志第一眼就应定位收集器类型:
立即学习“Java免费学习笔记(深入)”;
-
Parallel(吞吐量优先):日志中频繁出现
PSYoungGen、ParOldGen、Full GC (Ergonomics);Full GC 通常标记为[Full GC (System.gc())或(Ergonomics) -
CMS(已废弃):有明确阶段标识,如
[GC[YG occupancy、[CMS-concurrent-mark-start]、[CMS-concurrent-abortable-preclean];并发阶段日志独立成行,且不带“GC”前缀 -
G1(默认JDK9+):以
G1 Evacuation Pause开头,区分 young / mixed 暂停;mixed GC 日志会注明(mixed),并列出被回收的 old region 数量;常见提示如to-space-exhausted或evacuation failure表示内存压力大 -
ZGC / Shenandoah:日志简洁,强调低延迟特性;ZGC 日志以
ZGC开头,含Pause Mark Start、Pause Relocate Start;Shenandoah 则有Concurrent cycle、Init Mark、Final Mark等阶段,且多数操作是并发的,暂停极短
重点关注的指标与异常信号
光看格式不够,需结合数值判断健康度:
- 年轻代回收频率过高(如 1~2 秒一次):可能是 Eden 太小、对象生命周期长、或存在隐式对象创建(如 String.intern、大量临时包装类)
- 老年代持续增长不下降:说明对象过早晋升或存在内存泄漏;注意 Full GC 后老年代仍居高不下,尤其在 Parallel 或 CMS 下
-
G1 的 Mixed GC 频繁且效果差(如每次只回收少量 old region,但 old gen 仍在涨):可能需调大
-XX:G1MixedGCCountTarget或降低-XX:G1HeapWastePercent -
ZGC/Shenandoah 出现
Allocation Stall或Failed to allocate:说明并发标记/转移跟不上分配速度,需检查堆大小或升级硬件 - real time 远大于 user+sys time:可能受系统资源争抢(如 CPU 被抢占、内存页交换 swap)、或 JVM 陷入 safepoint 竞争
配合其他参数让日志更实用
单靠 PrintGCDetails 有时信息不足,建议组合使用:
-
-Xloggc:/path/to/gc.log将日志输出到文件(JDK8 及以前)或-Xlog:gc*:file=/path/to/gc.log:time,tags,level(JDK9+ 统一日志框架) -
-XX:+PrintGCTimeStamps(已与 DateStamps 冲突,JDK9+ 推荐用-Xlog替代) -
-XX:+PrintGCApplicationStoppedTime查看 STW 总耗时,辅助定位 GC 外的停顿源 -
-XX:+PrintAdaptiveSizePolicy(Parallel/G1)观察 JVM 自适应调优过程,比如 Survivor 区动态调整、阈值升降 - JDK11+ 强烈推荐直接使用
-Xlog:gc*,gc+ref*,gc+heap*,gc+ergo*,支持分级、过滤、输出格式控制,比旧参数更灵活可靠


















