线上OOM需按“现象→类型→现场→根因→修复”链路推进:先确认是否内存泄漏(老年代持续攀升、GC overhead频繁等),再据报错关键词锁定类型,及时保留GC日志、堆转储等现场,最后用MAT通过Leak Suspects、Dominator Tree和Path to GC Roots定位泄漏对象及引用链。

线上 OOM 不能只靠重启或加内存,得顺着“现象→类型→现场→根因→修复”这条链路一步步推进。核心是先分清是不是真泄漏,再锁定对象、引用链和代码位置。
第一步:确认是不是内存泄漏,而不是单纯堆小或流量高
内存泄漏有典型特征,满足其中两条就高度可疑:
- 老年代使用率持续攀升,Full GC 后内存回落极少(比如只降 5%~10%,而非回到 30% 以下)
- GC 日志里频繁出现 GC overhead limit exceeded 或多次 Java heap space,且重启后几天内复现
- JVM 监控显示 Eden 区回收正常,但老年代像“只进不出”,每次 Full GC 后占用反而略升
- 服务卡顿与 GC 停顿强相关,比如每 2 分钟一次长达 2s 的 STW
第二步:快速锁定 OOM 类型,避免方向错误
看报错信息关键词,直接对应排查重点:
- Java heap space → 查堆内对象:重点关注静态集合、ThreadLocal、缓存、监听器未注销
- Metaspace → 查类加载:CGLIB 动态代理过多、热部署未清理、Spring Boot DevTools 残留
- Direct buffer memory → 查堆外内存:Netty 的 PooledByteBufAllocator 未释放、FileChannel.map() 大文件映射
- unable to create new native thread → 查线程数:线程池无界、异步任务未限制、日志框架创建大量守护线程
别一看到 OOM 就 dump 堆,元空间或直接内存溢出时 dump 堆没用。
立即学习“Java免费学习笔记(深入)”;
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
第三步:保留关键现场,优先获取有效证据
服务还能响应时,立刻执行三件事:
- 用 jstat -gc
1000 5 抓 5 秒 GC 趋势,看 YGC/FULLGC 频次和耗时变化 - 用 jcmd
VM.native_memory summary 快速判断是否堆外内存异常飙升 - 触发即时堆转储:jcmd
VM.native_memory summary + jmap -dump:format=b,file=/tmp/heap.hprof
如果已挂掉,确保启动参数含 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/dump/,否则下次只能干等。
第四步:用 MAT 定位泄漏对象和强引用链
打开 .hprof 文件后,按顺序操作:
- 点 Leak Suspects Report → 看顶部 “Problem Suspect” 是否标红,通常就是泄漏源头
- 进 Dominator Tree,按 “Retained Heap” 降序,找占用最大的类(如 byte[]、HashMap、ArrayList)
- 右键该类 → Path to GC Roots → with all references,重点看 “exclude weak/soft references”
- 逐层展开引用链,直到找到业务类名(如 UserService、CacheManager),再顺藤摸到静态字段、ThreadLocal 或单例 Bean
常见泄漏路径举例:static HashMap → value 是 Controller 实例 → 其中持有 Request 对象 → Request 持有大量参数和输入流 → 整条链无法回收。

















