jvm内存泄漏排查需分四步:一用jstat观察gc趋势初筛;二通过自动或手动方式获取有效堆快照;三用mat分析leak suspects、dominator tree和gc roots定位泄漏源;四结合代码修复并压测验证。

JVM内存泄漏排查不是一次性的命令执行,而是一套有节奏、分阶段的实战流程。核心在于“早发现、准定位、快验证”,避免等OOM才动手。
一、先盯住现象,用jstat快速初筛
别急着dump,先看运行时趋势:
- 执行jstat -gcutil
2000 ,重点观察O列(老年代使用率)是否每次Full GC后只回落一点点,且最低值逐轮抬高; - 同时关注FGC次数是否明显增加、FGCT(Full GC耗时)是否持续拉长;
- 若E列频繁打满、YGC很多但O列仍稳步上升,说明对象晋升过快,可能是大对象直入老年代或Survivor区过小。
二、抓取有效快照,优先启用自动Dump机制
生产环境必须前置配置,而非临时补救:
- 启动参数加-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/dump/,确保OOM前一刻的现场被完整捕获;
- 若已高度怀疑但尚未OOM,可用jmap -dump:live,format=b,file=heap.hprof
手动抓取(注意避开高峰,该操作会STW); - 不推荐用jmap -histo粗略统计,它只能看数量,看不出引用关系和生命周期。
三、用MAT精准定位泄漏点
打开hprof文件后,按顺序走三步:
- 先看Leak Suspects Report,MAT会自动标出最可疑的1–3个对象及引用链;
- 再切到Dominator Tree,按Retained Heap排序,找深堆最大的类(比如某个静态Map、ThreadLocal变量);
- 对目标对象右键→Path to GC Roots,选“exclude weak/soft references”,看谁在强引用它——这才是真正的持有者。
四、结合业务代码验证与修复
工具给出的是线索,最终要回归代码逻辑:
- 常见泄漏源:静态集合未清理、ThreadLocal未remove、监听器/回调未注销、缓存无淘汰策略;
- 验证方式:修复后重启,用相同流量压测,观察jstat中O列是否不再阶梯式上升;
- 上线前建议加内存监控告警,例如老年代使用率连续5分钟>85%就触发通知。











