oom发生时应先看日志确认错误类型,再通过系统和gc表现区分突发性崩溃与渐进式泄漏,及时抓取堆快照,最后用mat分析泄漏对象及其gc roots引用链。

OOM发生时,第一反应不是重启,而是快速锁定“谁在吃内存”和“为什么吃不完”。面试官想看的不是工具命令的罗列,而是你有没有清晰的现场判断逻辑、优先级意识和生产敬畏心。
第一步:看日志,确认OOM类型
先翻应用日志,找到完整的错误堆栈。JVM的OOM不是一种错误,而是多种——每种对应不同内存区域:
- java.lang.OutOfMemoryError: Java heap space → 堆内存不够,重点查对象分配和泄漏
- java.lang.OutOfMemoryError: Metaspace → 类太多,关注动态代理、热部署、类加载器
- java.lang.OutOfMemoryError: Direct buffer memory → NIO直接内存爆了,查ByteBuffer.allocateDirect()调用和清理
- java.lang.OutOfMemoryError: unable to create new native thread → 不是内存不足,是线程数超限(ulimit或线程池失控)
不读完这行报错就动手分析,等于蒙眼修车。
第二步:看系统和GC表现,区分“爆炸型”还是“慢性病”
用top -p
- 如果FGC次数猛增 + OU(老年代使用率)居高不下 → 大对象/内存泄漏,老年代回收失败
- 如果YGC频繁但EU(Eden区使用率)很快打满 → 短生命周期对象暴增,比如日志刷屏、循环构造DTO
- 如果GC几乎不触发,但RSS一路冲顶 → 可能是堆外内存问题(DirectByteBuffer、JNI、Netty PooledByteBufAllocator未释放)
别只盯着“内存用了多少”,要看“内存为什么用不完”。GC频率和回收效果,比绝对数值更有诊断价值。
第三步:抓现场,决定dump时机和方式
OOM后JVM可能已卡死,不一定还能jmap。所以分两种情况处理:
-
服务还在运行但响应极慢:立刻执行jmap -dump:live,format=b,file=heap.hprof
。加live参数可跳过不可达对象,更快更准 - 已经OOM崩溃但配置了自动dump:检查-XX:HeapDumpPath指定路径下是否有.hprof文件。没有?说明参数没生效或磁盘写满
注意:jmap会触发STW,大堆可能卡住几十秒。如果服务完全不可用,宁可先保留现场再dump,别盲目操作。
第四步:离线分析,聚焦“谁占最多”和“谁拦着不放”
把hprof文件拖进MAT(Memory Analyzer Tool),核心就两步:
- 点Leak Suspects Report → 快速定位Top 1~2个可疑对象(比如一个ArrayList占了85%堆)
- 右键该对象 → Path to GC Roots → with all references → 看清楚是哪个Service、哪个定时任务、哪行add()把它一直挂着
真正难的不是找对象,而是解释“为什么这个引用链不该存在”。比如静态Map缓存了ResponseEntity,而ResponseEntity里又持有了整个HTTP请求体——这就是设计缺陷,不是代码bug。










