oom应急处理需在前3分钟快速确认类型、保留现场、锁定方向:先看日志判别oom类型,再用jstat验证gc状态,优先启用自动heapdump,最后聚焦静态集合、资源泄漏等高频根因。

一、看日志和监控,30 秒内判别 OOM 类型
先盯住错误信息本身,它直接指明战场在哪:
- java.lang.OutOfMemoryError: Java heap space → 堆内存区域,重点查老年代占用、对象堆积、缓存泄漏
- java.lang.OutOfMemoryError: Metaspace → 类元数据区,查动态代理、反射、热部署、类加载器是否泄漏
- java.lang.OutOfMemoryError: Direct buffer memory → 堆外内存,排查 NIO、Netty、文件映射、ByteBuffer.allocateDirect 调用
- java.lang.OutOfMemoryError: unable to create new native thread → 线程资源耗尽,查线程数、线程池配置、Xss 大小、系统 ulimit 限制
- GC overhead limit exceeded → 不是内存绝对不够,而是 GC 效率崩了(比如 98% 时间在 GC,只回收 2% 内存),本质仍是堆压力问题
二、用 jstat 实时观察 GC,1 分钟内验证是否真 OOM
执行:jstat -gcutil
- O(Old):持续 ≥95% 且 Full GC 后不回落 → 堆内对象堆积或泄漏
- FGC / FGCT:Full GC 频次突增(如从几小时一次变成每几十秒一次)→ 回收已失效,内存正在失控
- GCT:总 GC 耗时占比飙升(>30%)→ JVM 已陷入 GC 泥潭,服务必然卡顿
如果 O 和 FGC 同时拉满,基本可断定是堆内存 OOM,进入下一步;否则转向线程、Metaspace 或堆外排查路径。
三、保留现场,慎用 dump,优先启用自动机制
别急着手动 jmap —— 它会触发 STW,可能让本已脆弱的服务彻底卡死。更稳妥的做法是:
- 若服务尚未完全不可用,且已提前配置了 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/dumps/,则等 OOM 自然触发,文件会自动生成
- 若未配置,但进程还活着、响应缓慢,可用 jmap -dump:live,format=b,file=heap.hprof
,加 live 参数减少干扰,降低卡顿风险 - 务必先保留一台“案发现场”实例不重启,同时滚动重启其他实例保障业务;dump 文件下载后,用 MAT 打开看 Dominator Tree 和 Leak Suspects 报告
四、结合常见根因,快速缩小代码范围
不用从头翻代码,先聚焦高频雷区:
- 静态集合类:static Map / List / Cache,尤其没设上限、没过期、没清理逻辑的本地缓存
- 未关闭资源:数据库连接、文件流、HTTP 客户端、MQ 消费者,长期持有导致句柄和内存双泄漏
- 定时任务累加:每分钟往 ArrayList 里 addAll 全表数据,却从不清空
- 大对象直入老年代:单次分配 > -XX:PretenureSizeThreshold 的对象,绕过年轻代直接进老年代,撑爆老年代空间
- 线程创建失控:没走线程池,每次请求 new Thread();或 Xss 设置过大(如 2MB),少量线程就吃光栈内存
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











