类型一:Java heap space(堆内存溢出)

java.lang.OutOfMemoryError: Java heap space

这是最常见的 OOM 类型,意思是堆内存不够用了。

可能的原因:

  • 堆内存设置太小
  • 内存泄漏:对象无法被回收,越积越多
  • 突然创建了超大对象或大量对象

类型二:GC overhead limit exceeded(GC 开销超限)

java.lang.OutOfMemoryError: GC overhead limit exceeded

这个 OOM 的意思是:GC 占用了太多时间,却回收不了多少内存。

JDK 的默认阈值是:GC 时间超过 98%,但回收的内存不到 2%,就会抛出这个错误。

通常这是内存泄漏的"前兆"——堆内存快满了,GC 频繁执行但效果甚微,最后彻底撑爆。


类型三:Metaspace(元空间溢出)

java.lang.OutOfMemoryError: Metaspace

JDK 8 之后,永久代被元空间取代,元空间使用的是本地内存。如果元空间溢出,说明加载的类太多了。

可能的原因:

  • 元空间设置太小
  • 动态生成的类太多(比如 CGLIB 动态代理、反射、JSP 等)
  • 类加载器泄漏

类型四:Direct buffer memory(直接内存溢出)

java.lang.OutOfMemoryError: Direct buffer memory

直接内存溢出,通常和 NIO 有关。

Java 的 NIO 可以使用 DirectByteBuffer 直接分配堆外内存,这部分内存不受堆大小限制,但受限于物理内存。如果直接内存用太多,就会报这个错。

常见于使用 Netty、Mina 等 NIO 框架的场景。


类型五:unable to create new native thread(无法创建新线程)

java.lang.OutOfMemoryError: unable to create new native thread

这个 OOM 的意思是:创建线程失败了。

每个线程都需要占用一定的栈内存,当线程数量太多时,系统没有足够的资源来创建新线程。

可能的原因:

  • 线程池配置不合理,最大线程数设太大
  • 线程泄漏:线程创建了没销毁,越积越多
  • 系统限制:操作系统对进程的最大线程数有限制

类型六:StackOverflowError(栈溢出)

java.lang.StackOverflowError

严格来说这不是 OOM,但也是常见的内存相关错误。

栈溢出通常是因为方法调用层次太深,比如递归没有正确的退出条件。