![图片[1]-深度梳理 OOM 排查方法论:内存泄漏、堆溢出、元空间逐一拆解-速优课](https://www.suyouke.com/wp-content/uploads/2026/07/doubao_img_2304x1728_20260721_213943-1024x768.png)
在Java开发中,**OOM(Out Of Memory)**几乎是每个程序员都会遇到的问题。
但真正拉开差距的,不是你有没有遇到过OOM,
而是——你有没有一套清晰的排查思路。
很多人一遇到OOM就慌:
重启服务
加大内存
盲目dump分析
结果问题反复出现,始终无法根治。
今天,我总结一套通用且实战有效的OOM排查方法论。
一、先搞清楚:你遇到的是哪种OOM?
OOM并不只有一种类型,不同类型,排查思路完全不同。
常见的几种:
1、Java Heap Space(堆内存溢出)
最常见
对象创建过多 / 内存泄漏
2、Metaspace(元空间溢出)
类加载过多
动态生成类(如代理、反射)
3、Direct Memory(直接内存)
NIO / Netty 使用不当
堆外内存未释放
4、GC Overhead Limit Exceeded
GC花了大量时间但回收很少
本质还是内存不够
第一原则:先看报错信息,确定类型,再动手!
二、观察监控:判断问题性质
不要一上来就分析dump,先看趋势:
关键指标:
- Heap使用率
- GC频率(尤其是Full GC)
- Old区占用情况
- 线程数变化
判断两种典型场景:
✅ 情况一:内存持续上涨(最危险)
高概率是:内存泄漏
特点:
- Full GC后内存仍然降不下来
- 使用量呈“阶梯式上升”
✅ 情况二:瞬间打满
高概率是:突发流量 / 大对象
特点:
- 短时间内飙升
- GC后恢复正常
这一步决定你后面的排查方向,极其关键。
三、获取现场:Heap Dump 是核心
定位OOM,本质就是一句话:
找到“谁占用了内存”
常用方式:
jmap -dump:format=b,file=heap.hprof <pid>
或者提前配置:
-XX:+HeapDumpOnOutOfMemoryError
注意:
- dump文件可能很大(几GB)
- 生产环境注意磁盘空间
四、核心分析:3个关键视角
使用工具:MAT(Memory Analyzer Tool)
重点看3个地方:
1、Histogram(对象分布)
看哪些类占用最多内存
2、Dominator Tree(支配树)
找“真正的大对象”
重点关注:
- 占比异常的集合(List / Map)
- 大数组 / 大缓存
3、GC Roots(引用链)
回答一个关键问题:
❗ 为什么这个对象没有被回收?
五、常见OOM根因(90%都在这里)
根据经验,大多数OOM都可以归类为:
1. 集合无限增长
static List data = new ArrayList<>();
data.add(obj);
没有上限、没有清理机制
2. 缓存使用不当
没有过期策略
没有容量限制
3. 线程泄漏
线程池未关闭
线程不断创建
4. 连接/资源未释放
数据库连接
文件流
网络连接
5. 类加载过多(Metaspace)
动态生成类(如代理类)
记住一句话:
OOM ≠ 内存不够,而是“内存被错误使用”
六、排查流程总结(建议收藏)
给你一套可以直接用的流程:
OOM排查6步法:
1、看异常日志(确定类型)
2、看监控(趋势 vs 突发)
3、获取Heap Dump
4、分析大对象(Histogram / Dominator)
5、找引用链(GC Roots)
6、回到代码定位问题
核心逻辑只有一句话:
谁占内存 → 为什么不释放 → 哪段代码导致
七、一些实战建议(很重要)
✅ 必做:
- 开启OOM自动dump
- 配置内存监控报警
- 定期分析GC日志
❌ 避免:
- 用全局静态集合缓存数据
- 无限制缓存
- 频繁创建大对象
八、结语
很多人把OOM当作“运维问题”,
但实际上,它更像是:
代码设计问题 + 资源管理问题
当你掌握了一套系统化排查思路之后:
OOM不再是“事故”,而是“可控问题”。








请登录后查看评论内容