在 JVM 运行时数据区中,哪些区域可能抛出 OutOfMemoryError,触发条件分别是什么?
考察说明
考查对 JVM 运行时内存区域的划分及各区域 OOM 触发机制的理解。
回答思路
- 【回答框架 1】JVM 运行时数据区包括程序计数器、虚拟机栈、本地方法栈、堆、方法区(含运行时常量池)以及直接内存。除程序计数器外,其余区域都可能抛出 OutOfMemoryError。
- 【回答框架 2】堆是所有线程共享的区域,存放对象实例。当堆中对象无法被 GC 回收且堆内存不足以分配新对象时,抛出 java heap space 的 OOM。常见原因包括内存泄漏或堆容量设置过小。
- 【回答框架 3】虚拟机栈和本地方法栈各自对应线程栈。当线程请求的栈深度超过 JVM 允许的最大深度时抛出 StackOverflowError;当栈内存无法申请到足够空间时(如线程数过多或单个栈大小设置过大)抛出 unable to create new native thread 的 OOM。
- 【回答框架 4】方法区(在 Java 8 之后由元空间实现,使用本地内存)存储类元数据、常量、静态变量等。当加载的类数量过多或动态生成大量类时,元空间耗尽会抛出 Metaspace OOM。运行时常量池在 JDK 6 及之前位于永久代,也会因常量过多而 OOM。
- 【回答框架 5】直接内存由 NIO 等使用,不在堆内。当分配的直接内存累计超过可用内存上限(可通过 MaxDirectMemorySize 设置)时抛出 Direct buffer memory 的 OOM。
- 【关键点 1】OOM 可能发生在堆、虚拟机栈、本地方法栈、方法区(元空间)和直接内存,程序计数器不会 OOM。
- 【关键点 2】堆 OOM 典型错误为 java.lang.OutOfMemoryError: Java heap space。
- 【关键点 3】线程栈 OOM 典型错误为 unable to create new native thread。
- 【关键点 4】方法区 OOM 在 Java 8 后体现为 java.lang.OutOfMemoryError: Metaspace。
- 【关键点 5】直接内存 OOM 类似 java.lang.OutOfMemoryError: Direct buffer memory。
- 【易错点 1】混淆栈溢出与栈 OOM:栈深度超限是 StackOverflowError,内存不足才是 OOM。
- 【易错点 2】误认为元空间不受限制:虽然默认使用本地内存,但受物理内存和 MaxMetaspaceSize 约束。
- 【易错点 3】忽略直接内存的 OOM 可能性,其不受堆大小限制。