内存泄漏早期最典型特征:老年代/堆内存呈缓慢、持续、不可逆的上涨,但还没严重到频繁Full GC、OOM。

这个阶段最容易定位根因,核心思路是:监控趋势 → 定位泄漏区域 → 抓取堆快照 → 分析泄漏对象 → 定位代码。
下面给你一套生产环境可直接落地的排查流程,从简单到深入,不影响业务。
先排除正常内存使用、堆设置过小等情况。
通过监控看 堆内存/老年代 趋势:
jstat -gcutil <pid> 1000 10 # 每1秒输出一次GC情况,共10次
重点看 3 个指标:
O:老年代使用率FGC:Full GC 次数FGCT:Full GC 总耗时泄漏早期特征:
O 持续缓慢上升(比如从 30% → 40% → 50%)FGC 很少(0~几次)只要满足「老年代只涨不跌」,基本就是内存泄漏。
绝大多数泄漏是 堆内泄漏,极少数是堆外。
先按堆内泄漏排查,效率最高。
不需要重启、不需要压测、低影响,生产直接用。
jmap -dump:format=b,file=leak.hprof <pid>
leak.hprof 二进制堆转储文件小提示:JDK8+ 加 -dump:live 可以只抓存活对象,文件更小:
jmap -dump:live,format=b,file=leak.hprof <pid>
最常用、最稳定的工具:Eclipse MAT(免费、强大)
选择 Acquire Heap Dump / Open Heap Dump
MAT 会自动生成:Leak Suspects Report
它会直接告诉你:
看对象实例数,找数量异常多的业务对象(你的自定义类)
右键对象 → 查看 GC Root 引用链
只看 强引用链,泄漏一定在这里
你在分析时,优先排查这 5 类代码,90% 泄漏都在这里:
private static List<Object> list = new ArrayList<>(); // 只add不remove,对象永远无法回收
private static ThreadLocal<Object> tl = new ThreadLocal<>(); // 线程池中的线程长期存活,ThreadLocalMap 一直持有对象
private static Map<String, Object> CACHE = new HashMap<>(); // 无过期、无淘汰,无限增长
如果不能用MAT,可以先用命令粗定位:
jmap -histo <pid> | head -20
输出:实例数、字节数、类名
找自定义类、实例数异常高的类,就是怀疑对象。
不用等问题爆发,配置监控即可:
以上就是Java内存泄漏早期排查流程(未触发频繁Full GC前)的详细内容,更多关于Java内存泄漏早期排查的资料请关注本站其它相关文章!
您可能感兴趣的文章: