Java垃圾回收日志分析需分四步:一、按JDK版本正确配置结构化日志参数;二、用GCViewer定位最长单次停顿及对应GC类型;三、结合堆使用率与GC类型交叉验证根因;四、辅以GCEasy、jstat、APM和堆快照深入归因。

Java 垃圾回收日志是诊断内存问题最直接的一手数据,关键不在“有没有日志”,而在“日志能不能看清、能不能定位到根因”。用对参数生成结构化日志,再借助工具可视化+交叉验证,才能高效揪出停顿长、吞吐低、频繁 Full GC 的真实诱因。
一、先确保日志本身能被正确解析
不同 JDK 版本日志参数差异大,配错就白记:
- JDK 8 及更早:必须组合使用 -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -Xloggc:gc.log,缺一不可;建议加 -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=10M 防止日志滚丢
- JDK 9–10:可用 -Xloggc:gc.log 兼容旧参数,但推荐过渡到统一日志格式
- JDK 11 及以上:-Xloggc 已废弃,必须用 -Xlog:gc*:file=gc.log:time,uptime,pid,tags;若需分析对象晋升年龄,务必显式加上 gc,age 标签
- 避免混用日志格式(比如 G1 日志里夹 ParallelGC 记录),GCViewer 会漏读或报错
二、用 GCViewer 快速定位最长单次停顿
它不替代人工判断,但能把“哪一次最卡”从几千行日志里秒标出来:
- 启动后加载 gc.log,点菜单 View → Show Pause Chart 调出停顿时间折线图
- 图中最高点对应的时间戳,回到原始日志里搜索该时刻附近的完整 GC 行(例如 2024-05-20T14:22:36.123+0800: 12345.678: [GC pause (G1 Evacuation Pause) (mixed), 0.3214567 secs])
- 重点看三块:pause 类型(young/mixed/full)、real 耗时(STW 真实停顿)、堆前后变化(如 Old: 1800M->1790M(2048M) 是否逼近上限)
- 如果出现孤立尖峰(均值 30ms,某次 780ms),优先查 CMS 降级、G1 Mixed GC 混入大量老年代 Region、ZGC Relocate 阶段卡顿
三、结合堆趋势与 GC 类型交叉验证原因
单看停顿时间容易误判,必须联动其他图表:
立即学习“Java免费学习笔记(深入)”;
- 打开 Heap Usage 图:若最长停顿时刻堆使用率接近 MaxHeap(比如 3980M/4096M),大概率是内存不足或碎片导致晋升失败
- 查看 GC Types 饼图或柱状图:如果 Full GC 占比异常高,且日志里带 (Ergonomics) 或 (Metadata GC Threshold),说明不是代码问题,而是元空间爆了或 G1 自适应策略失效
- 对比 Young Gen 和 Old Gen 回收频率:年轻代 GC 过密(比如每 2 秒一次),可能是 Eden 太小或对象存活率高;老年代增长缓慢但某次突增,要查是否有大对象直接分配或批量缓存未清理
四、辅助工具与进阶建议
GCViewer 解决“定位”,其他工具补足“归因”和“验证”:
- GCEasy:上传 gc.log 后自动生成泄漏风险评分、吞吐量/停顿统计、调优建议(比如“建议增大 -Xmn”),适合快速概览
-
jstat -gc
:实时观察当前 JVM GC 频率与各区内存占用,验证日志结论是否仍在复现 - 导出 CSV + 关联 APM:在 GCViewer 中导出停顿时间序列 CSV,叠加应用响应延迟曲线,确认高停顿是否真造成业务超时
- 生产环境别只靠日志:配合 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/dump/,OOM 时自动抓堆快照,用 MAT 或 JProfiler 深挖对象引用链


















