核心三步:采集日志(JDK8/10用-XX:+PrintGCDetails等,JDK11+用-Xlog:gc*:file=gc.log:time,tags,pid)、读懂关键字段(关注Allocation Failure、Eden/Survivor/老年代变化、real停顿时间)、结合现象定位问题(如Minor GC后Survivor高位→提前晋升;Full GC后老年代不降→内存泄漏或大对象驻留)。

直接上手做,不绕弯。核心就三步:采集日志、读懂关键字段、结合现象定位问题。
一、先让 JVM 吐出有用的 GC 日志
不同 JDK 版本写法不一样,别混用:
- JDK 8/9/10:加这组参数启动应用
-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:gc.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=100M - JDK 11+(含 ZGC、Shenandoah):
-Xlog:gc*:file=gc.log:time,tags,uptime,pid -Xlog:gc+heap=debug -Xlog:gc+ref=debug
特别注意:用gc*覆盖所有 GC 相关事件,time和pid是多实例排查的刚需。
二、盯住日志里真正能说明问题的几行
不用通读,重点看三类典型行:
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
-
Young GC 行:比如
2026-10-09T08:22:15.342+0800: 12345.678: [GC (Allocation Failure) [PSYoungGen: 1228800K->184320K(1310720K)] 2457600K->1413120K(4194304K), 0.1234567 secs]
关注点:括号里是不是Allocation Failure?回收后 Young 区用了多少(184320K)?前后差值是否小得可疑(说明对象没被回收,可能提前晋升)? -
Full GC 行:比如
2026-10-09T08:25:44.111+0800: 12567.890: [Full GC (Ergonomics) [PSOldGen: 2129920K->2097152K(2883584K)] 3538944K->3538944K(4194304K), [Metaspace: 123456K->123456K(1179648K)], 4.5678901 secs]
关键看触发原因(Ergonomics是 JVM 自动决策,System.gc()就要查代码)、老年代回收前后几乎没变(2129920K→2097152K),说明不是内存不足,而是对象“卡”在老年代出不去。 -
ZGC / G1 的阶段日志:比如
[12.345s][info][gc]GC(7) Pause Mark Start
[12.348s][info][gc]GC(7) Pause Mark End 3.212ms
这类日志要对时间戳做减法,看各阶段耗时是否异常——标记阶段超 5ms、转移阶段超 2ms,就得怀疑堆碎片或对象图太深。
三、用工具把日志“翻译”成结论
手动算几十万行日志效率低还易错,推荐两个落地方式:
立即学习“Java免费学习笔记(深入)”;
-
GCEasy 网页版:上传 gc.log,3 秒生成报告。重点关注它标红的项:
— “GC Overhead > 98%” → 应用大部分时间在 GC,不是在干活;
— “Frequent Minor GC” + “High Old Gen Promotion Rate” → Survivor 区太小或对象太大,正在往老年代狂塞;
— “Longest GC Pause” 超过业务 SLA(比如支付系统要求 -
命令行快速验证:用
grep和awk快速统计
grep "Full GC" gc.log | wc -l → 查全天 Full GC 次数
awk '/Pause Young/ {sum += $NF} END {print sum/NR}' gc.log → 算平均 Young GC 耗时
比打开文件一行行翻快得多。
实战项目不需要从零造轮子。拿线上一段 1 小时的 gc.log,按上面三步走一遍,你就能说出:为什么每 3 分钟一次 Full GC,为什么 YGC 耗时突然从 20ms 涨到 150ms,以及该调哪个参数。真实问题,就藏在那几行带时间戳和箭头的文本里。

















