项目是 JDK 8,下面按这个环境给你一套实操流程。
一、OOM 排查
1. 事先埋点(最重要)
启动参数加上:
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/dump/
OOM 时自动生成 java_pidxxx.hprof 文件,没有它就只能靠现场命令抓。
2. 运行中现场抓取
jps -l # 找到进程号
jmap -histo:live <pid> | head -30 # 快速看哪些类实例最多、占内存最大(会触发一次Full GC,低峰期执行)
jmap -dump:live,format=b,file=heap.hprof <pid> # 导出完整堆快照(STW几秒,生产慎用)
3. 用 MAT 分析 dump
工具:Eclipse MAT(Memory Analyzer Tool),打开 .hprof 文件:
- Leak Suspects 报告:自动给出泄漏疑点,直接告诉你哪个类占了百分之多少的堆
- Dominator Tree:按内存占用排序列出对象,找到最大的那个
- 右键对象 → Path to GC Roots (exclude weak/soft references):看到完整的引用链,比如
XXController.cache → HashMap → 100万个User对象,引用链的持有者就是泄漏代码的位置
4. 常见 OOM 类型对症
| 报错信息 | 方向 |
|---|---|
Java heap space | 堆内存泄漏/不够,走上面 MAT 流程 |
Metaspace | 反射/CGLIB 动态生成类没释放,看 Class.forName、动态代理 |
unable to create new native thread | 线程数爆了,jstack <pid> 看线程数和线程名 |
Direct buffer memory | NIO 堆外内存,-XX:MaxDirectMemorySize + Netty 相关 |
5. 常见根因(代码层面)
- 静态 Map/List 只 put 不 remove(本地缓存无上限、无过期)
- ThreadLocal 没 remove(线程池场景必漏)
- 监听器/回调注册后没注销
- 一次性查全表的大 SQL 结果集
二、频繁 Full GC 排查
1. 先看 GC 行为定性
jstat -gcutil <pid> 1000 # 每秒打印一次
看两列关键信息,连续观察 1 分钟:
- O(老年代)持续涨,Full GC 后降不下来 → 内存泄漏,回到 OOM 排查流程
- FGC 数字持续增加但每次 O 能降下去 → 老年代进对象太快:大对象、Young 区太小、Survivor 放不下提前晋升
- FGC 次数和 元空间/M 区 相关 → 类加载问题
2. 打开 GC 日志(JDK 8 语法)
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/data/gc.log
把 gc.log 丢到 gceasy.io(网页版,免费)分析,会告诉你:晋升失败原因、大对象分配、GC 停顿分布。
3. 定位是谁在分配内存
- Arthas(阿里开源,生产可用,推荐):
curl -O https://arthas.aliyun.com/arthas-boot.jar java -jar arthas-boot.jar # 选进程 dashboard # 总览,直接看堆各区和FGC次数 heapdump /tmp/heap.hprof # 也能导出dump给MAT profiler start / profiler stop # 生成内存分配火焰图,直接看到哪个方法在疯狂分配对象 - JProfiler / async-profiler:CPU/内存火焰图,定位到具体分配热点方法
4. 常见根因
- 系统缓存放本地大对象(一次加载数十万条进内存)
- 大对象(超过
-XX:PretenureSizeThreshold或 Young 区一半)直接进老年代 - 显式调用
System.gc()(排查依赖库,可加-XX:+DisableExplicitGC) - Young 区太小导致对象过早晋升,Full GC 频繁但不是泄漏(调大
-Xmn或改用 G1)
三、快速决策树
频繁FGC
├─ jstat 看 O 区 Full GC 后是否回落
│ ├─ 降不下来 → 泄漏 → jmap -histo → MAT → 引用链定位类
│ └─ 降得下来 → 分配太快 → GC日志/gceasy → Arthas profiler 火焰图找分配热点
└─ 伴随 OOM → 先确保 HeapDumpOnOutOfMemoryError 开着,dump 后 MAT Leak Suspects
建议现在就检查一下线上启动脚本有没有加 HeapDumpOnOutOfMemoryError 和 GC 日志参数——这两个是事后排查的生命线,OOM 时没有 dump 就只能靠猜了。
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/qq_28919337/article/details/164851119



