直接看gc日志是定位频繁gc根因最快最准的入口,需关注full gc触发原因、关键指标趋势、时间与停顿特征,并确保启用-xloggc等必要参数,再结合jstat、jmap、mat闭环归因。

直接看 GC 日志,是定位频繁 GC 根因最快、最准的入口。它不依赖代码改动或重启,能告诉你“谁在什么时候、因为什么、干了什么”。
重点抓三类日志线索
-
Full GC 触发原因关键词
-
Allocation Failure:Eden 耗尽 → 对象晋升老年代失败 → 老年代空间不足 → Full GC(最常见) -
Metaspace allocation failure:元空间满,多见于动态代理、热部署、反复加载类 -
Full GC (System):代码或第三方库显式调用了System.gc() -
concurrent mode failure或promotion failed:CMS 收集器下老年代预留空间不够,担保失败
-
-
关键指标趋势
- 老年代使用率(O 列)持续缓慢爬升,GC 后下降极少 → 内存泄漏迹象
- 元空间使用率(M 列)单向增长,不回落 → 类加载泄漏
- Eden 区每次 Minor GC 后,晋升到老年代的字节数(比如
PSYoungGen→ParOldGen的 transfer size)异常大 → 新生代太小或对象寿命偏长 - Full GC 频次:生产环境正常应是几小时甚至几天一次;若缩短至 5–10 分钟一次,必须干预
-
时间与停顿特征
- 单次 Full GC 耗时超过 500ms,且多次累计停顿时间占总运行时间 >15% → 已影响服务 SLA
- GC 日志中出现连续多个
Full GC,中间几乎没有业务日志 → 可能陷入 GC 恶性循环(如线程池拒绝导致对象滞留老年代)
确保日志可用的硬性前提
- JVM 启动时必须带上这些参数(没配就补,动态 attach 不现实):
-
-Xloggc:/path/to/gc.log(指定路径) -
-XX:+PrintGCDetails(打印详细过程) -
-XX:+PrintGCDateStamps(带时间戳,方便关联业务日志) -
-XX:+PrintHeapAtGC(每次 GC 打印堆各区域占用,辅助判断晋升行为)
-
快速初筛方法(不用工具,命令行即可)
- 统计 Full GC 次数和间隔:
grep "Full GC" gc.log | awk '{print $1,$2}' | head -20 - 查看最近 10 次 Full GC 的耗时:
grep "Full GC" gc.log | tail -10 | awk '{print $(NF-2)}' - 看老年代使用率变化(假设日志含
[PSOldGen: xxxK->yyyK):grep "PSOldGen" gc.log | tail -20 | awk -F'->' '{print $2}' | cut -d'K' -f1
日志不是终点,而是起点。它告诉你“发生了什么”,下一步要结合 jstat 实时观察、jmap 抓堆快照、再用 MAT 定位具体对象,才能闭环归因。











