← 每日面试题 学习看板

在什么情况下会发生OOM?都有哪些类型的OOM?都如何解决和监控?

面试题/00java/03JVM/07OOM 与异常处理/在什么情况下会发生OOM?都有哪些类型的OOM?都如何解决和监控?.md

面试记录 2026-09-21

题目:在什么情况下会发生OOM?都有哪些类型的OOM?都如何解决和监控?

难度:high

标签:jvm/oom, general/knowledge, difficulty/high

评分:⭐⭐⭐☆☆(3/5)

我的回答

OOM 的本质就是内存对象无法再分配,原有的内存已经被占满了。 Out of memory error 它本身无法再分配内存对象。一种是内存泄露,所有的堆空间都被占满了,垃圾回收也回收不到,然后达到一定百分比,具体是多少没有印象了,应该有个百分比,并不是 100%。另外有方法区,方法区如果占满了,也会导致 OOM,占溢出。我印象中主要是这 3 种 OOM 产生方式,具体类型就是堆内存溢出、占溢出。和方法区溢出,也就是元空间溢出,对象的一存溢出。监控的话,监控内存使用情况,然后以及监控 GC 的次数频率,然后 GC 回收的比例。通过这些去监控具体的 OOM 的可能情况。内存比例如果是线性增长的话,没有被回收掉,每次是线性增长,就需要关注具体哪些对象产生了问题。然后去对应的监控,找到对应的对象进行分析处理,看是什么原因导致这些对象无法被回收,是内存出、方法区溢出,还是具体的哪些定义了大量的 class,比如说 class 加载,大量的那个 class 类加载导致内存溢出。哦,根据不同情况,因为大量 class 类加载基本上是反射这些东西用的导致的,就这样处理。然后内存溢出的话,是否是有不合理的对象循环创建?然后对应的进行调整。

点评

优点:

不足:

补充:

  1. Java heap space:堆溢出(最常见)
  2. Metaspace:元空间溢出(JDK 8+,替代永久代)
  3. GC overhead limit exceeded:GC 时间 >98% 但回收 <2%
  4. Direct buffer memory:直接内存溢出(Netty/NIO,受 -XX:MaxDirectMemorySize 限制)
  5. unable to create new native thread:线程过多导致栈溢出
  6. unable to make continuation:协程溢出
  7. Requested array size exceeds VM limit:数组过大
  8. Compressed class space:压缩类空间溢出

完整讲解

第一部分:知识重点剖析

核心考点定位:考察 OOM 的分类完整性+每种类型的触发场景+监控和解决手段。

知识点拆解:

  1. OOM 本质
  1. OOM 完整分类(HotSpot 常见 8 种)
类型消息触发场景
Java heap space堆溢出缓存无界、集合未清、监听器未反注册
GC overhead limit exceededGC >98% 但回收 <2%内存接近满但 GC 无法有效回收
Metaspace元空间溢出(JDK 8+)动态代理、CGLIB、Groovy 脚本、ClassLoader 泄漏
Direct buffer memory直接内存溢出NIO/Netty 未释放 DirectByteBuffer
unable to create new native thread线程过多Thread 未复用、线程池无上限
Requested array size exceeds VM limit数组过大一次申请超大数组
Compressed class space压缩类空间满-XX:CompressedClassSpaceSize 满
unable to make continuationLoom 协程溢出Java 21+ 虚拟线程相关
  1. 每种类型的典型根因
  1. 监控手段
  1. 解决手段矩阵
问题短期处置长期解决
堆溢出kill -9 + 换实例、扩堆修内存泄漏、优化分配
Metaspace 溢出调大 -XX:MaxMetaspaceSize排查 ClassLoader 泄漏
DirectBuffer 溢出kill + 重启显式释放、JDK 9+ Cleaner
GC overhead扩堆、换 GC 器修泄漏、优分配
线程过多kill 线程、扩容线程池化、ThreadLocal 管理
  1. 实战案例:Netty 内存泄漏

第二部分:考察方向与延伸递进

考察方向:

延伸递进面试题:

  1. Java heap space 和 GC overhead limit exceeded 有什么关系?
  1. 如何判断是内存泄漏还是正常的堆使用?
  1. Metaspace 溢出如何定位 ClassLoader 泄漏?
  1. DirectByteBuffer 泄漏怎么查?
  1. 生产 OOM 的应急 SOP 是什么?

第三部分:面试者参考回答(300-600 字口语化)

面试官您好,OOM 的本质就是JVM 认为无法通过 GC 解决内存不足,抛出 java.lang.OutOfMemoryError。

OOM 完整分类(HotSpot 常见 8 种):

  1. Java heap space:堆溢出,最常见
  2. GC overhead limit exceeded:GC 时间 >98% 但回收 <2%,通常是堆溢出的前兆
  3. Metaspace:元空间溢出(JDK 8+,替代永久代)
  4. Direct buffer memory:直接内存溢出,Netty/NIO 场景常见
  5. unable to create new native thread:线程过多导致栈溢出
  6. Requested array size exceeds VM limit:一次申请超大数组
  7. Compressed class space:压缩类空间满
  8. unable to make continuation:Java 21+ Loom 协程溢出

典型触发场景:

监控手段:

排查思路:

  1. 先看 OOM 类型(异常消息)
  2. 打开 dump,MAT 看 Dominator Tree 找最大对象持有者
  3. 看 Shortest Path to GC Roots 判断是不是被"不该引用的强引用"持有
  4. 如果是 Metaspace,用 GC.class_histogram 看 ClassLoader 数量
  5. 如果是 DirectBuffer,用 VM.native_memory 或 JFR 事件分析

解决矩阵:

一个实战案例:Netty 服务 Direct buffer memory OOM。现象是堆没满但进程挂掉。排查用 jcmd VM.native_memory 看 DirectByteBuffer 线性增长,定位到某个 handler 没 release() 掉 ByteBuf。修复:Netty 4.1+ 用 ReferenceCountUtil.safeRelease,JFR 加 jdk.DirectByteBuffer 事件监控。

一句话总结:OOM 排查三件套——堆 dump + GC 日志 + 原生内存追踪,配合 METASPACE 泄漏和 DirectBuffer 泄漏的专项排查,就能覆盖 95% 的生产 OOM 场景。