java内存泄漏排查需早发现、快定位、不扰民:通过jstat观测老年代持续上涨与full gc回收差,用arthas实时查热点对象及静态字段,结合jmap比对实例增长并mat分析引用链,聚焦静态集合、threadlocal、未关闭资源和无过期缓存四类高频问题。

生产环境 Java 内存泄漏排查,核心是“早发现、快定位、不扰民”——不能等 OOM 才动手,要在内存缓慢上涨阶段就捕获可疑对象和引用链。整个过程无需重启服务、不改代码、不依赖预埋监控,靠的是组合使用 JDK 自带命令 + Arthas + GC 日志分析。
看老年代趋势,确认泄漏特征
内存泄漏最直观的表现是老年代(Old Gen)持续上涨、Full GC 后回落极少。用 jstat 持续观测:
-
jstat -gc
2000 10 :每 2 秒输出一次 GC 统计,重点关注 OU(Old Used)是否逐轮上升、OGC(Full GC 次数)是否陡增 - 若每次 Full GC 后 OU 只下降一点点(比如 1800M → 1790M),说明大量对象跨代晋升且无法回收,极可能泄漏
- 搭配 jstat -gccause
5000 看触发原因,频繁出现 Allocation Failure 但回收效果差,就是典型信号
用 Arthas 实时抓热点对象
Arthas 是线上无侵入排查的首选工具,支持热插拔、秒级响应:
- dashboard:查看堆内存趋势、GC 频次、线程数,重点关注老年代使用率是否“只升不降”
- vmtool --action getInstances --className com.example.Order --limit 10:查业务类当前存活 Top 10 实例,快速识别异常增长对象
- vmtool --action getStaticField --className com.example.CacheManager --fieldName cache:检查静态字段是否持有不该长期存在的集合或缓存
- heapdump --live /tmp/heap.hprof:加 --live 只导出活跃对象,比全量 dump 更快更小,适合低峰期快速留证
比对对象增长,锁定泄漏源头
光看数量不够,要看出“谁在涨、怎么涨”:
- 执行 jmap -histo:live
> /tmp/histo-$(date +%s).txt ,间隔 5–10 分钟采集两次,对比文件中类实例数变化 - 重点盯住增量最大的前 3 类,例如 com.example.UserSession 从 200 增至 4800,就要立刻查它被谁引用
- 用 jmap -dump:format=b,file=/tmp/suspect.hprof
导出对应时刻快照,本地用 MAT 打开,查 “Path to GC Roots” 找强引用链
定向验证高发泄漏场景
不必大海捞针,优先检查这几类高频问题:
-
静态集合滥用:查
static Map, ?>或static List>是否只 put 不 remove - ThreadLocal 泄漏:用 thread -n 5 查活跃线程,再对业务线程(如 OrderExecutor)执行 ognl '@java.lang.Thread@currentThread().getThreadLocals()'
- 未关闭资源:检查数据库连接、HTTP 客户端、文件流是否用了 try-with-resources,或显式 close
- 缓存无过期策略:本地 GuavaCache、Caffeine 或自定义 Map 缓存,是否设置了 maximumSize / expireAfterWrite
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











