内存泄漏排查首看gc日志中老年代趋势:多次full gc后psoldgen/g1oldgen“回收后占用”持续上升(如6800k→7150k→7620k)、回落量锐减,且总容量不变,即为典型泄漏迹象;同时关注minor gc频率飙升、age 1对象占比超80%等早期信号。

日志分析是内存泄漏排查的第一道防线,不依赖复杂工具,却能快速圈定问题范围。关键不是看有没有报错,而是观察 GC 行为是否“失常”——正常回收有规律,泄漏则留下持续累积的痕迹。
看 GC 日志里的老年代趋势
重点盯紧 Full GC 后老年代(如 PSOldGen、G1OldGen 或日志中带 old/tenured 标签的段)的内存占用变化:
- 连续几次 Full GC 后,老年代“回收后占用”从 6800K → 7150K → 7620K,总容量不变,回落量越来越小,说明对象在堆积且无法释放
- 避免只看总堆(Heap)变化,新生代波动会掩盖老年代的真实压力
- JDK 8 日志找类似
[PSOldGen: 6800K->7150K(8192K)]的字段;JDK 11+ 统一日志则搜索Old或tenured关键字段
抓 Minor GC 异常飙升信号
新生代频繁 GC 往往是泄漏的早期表现,背后常有对象“不该晋升却硬挤进老年代”:
- Eden 区几秒就填满,Minor GC 间隔从分钟级缩到秒级
- 开启
-XX:+PrintTenuringDistribution后,日志中反复出现age 1: xxx bytes占比超 80%,说明大量对象跳过 Survivor 直接晋升 - 配合
jstat -gc <pid></pid>实时验证:若 YGCT(Young GC 总耗时)和次数在 10 分钟内激增 3 倍以上,而老年代最大容量(OGCMX)未变,基本可锁定晋升异常
结合应用日志交叉验证
GC 日志只说“哪里堵了”,应用日志能提示“谁干的”:
- OOM 前几分钟,是否集中出现某类接口调用日志?比如批量导出、定时任务触发后 GC 骤然恶化
- 是否有资源类警告?如 “Failed to close connection”、“Stream not closed” 等,指向未释放的连接或流
- 自定义监控埋点是否显示某缓存命中率骤降、size 持续增长?可能缓存未设过期或清理机制
确保日志本身“说得清”
如果当前日志信息不足,需立即补全 JVM 启动参数:
- JDK 8 及以下:
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:gc.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/dump - JDK 9+:
-Xlog:gc*:file=gc.log:time,level,tags:filecount=5,filesize=100m - 务必启用
HeapDumpOnOutOfMemoryError,OOM 时自动生成 .hprof 文件,后续可用 MAT 工具深挖











