JVM内存区域划分为五个核心部分:程序计数器、Java虚拟机栈、本地方法栈(线程私有);堆、方法区(线程共享);其中堆存放对象实例,方法区存储类信息与静态数据,直接内存虽非运行时数据区但被NIO频繁使用。

JVM 内存区域划分为五个核心部分,各自承担明确职责,共同支撑 Java 程序的运行、对象生命周期管理与垃圾回收。理解它们的关键不在于死记硬背,而在于把握“谁用、何时用、是否共享”这三个维度。
线程私有区域:程序计数器、虚拟机栈、本地方法栈
这三块内存随线程创建而分配,随线程结束而销毁,天然线程安全,无需同步。
- 程序计数器:记录当前线程正在执行的字节码指令地址,是实现分支、循环、异常跳转和线程切换恢复的基础;它是唯一不会发生 OutOfMemoryError 的区域。
- Java 虚拟机栈:为每个方法调用分配栈帧,存储局部变量表、操作数栈、动态链接、方法出口等信息;栈深度超限(如无限递归)会抛出 StackOverflowError。
- 本地方法栈:功能类似虚拟机栈,但服务于 JNI 调用的 native 方法(如 C/C++ 编写的代码),具体实现由虚拟机决定。
线程共享区域:堆与方法区
这两块区域被所有线程共用,因此对象创建、类加载、静态变量修改等操作需考虑并发控制。
- 堆(Heap):JVM 中最大的内存区域,几乎所有对象实例和数组都在此分配;是垃圾收集器管理的主要区域,常按对象存活时间划分为新生代(Eden + Survivor0/Survivor1)和老年代;支持 TLAB(线程本地分配缓冲区)优化多线程内存分配效率。
- 方法区(Method Area):存储已被 JVM 加载的类信息、常量池、静态变量、即时编译后的代码等;在 JDK 8 及之后,HotSpot 用元空间(Metaspace)替代永久代(PermGen),元空间使用本地内存,不再受 -XX:MaxPermSize 限制,而是通过 -XX:MaxMetaspaceSize 控制上限。
直接内存:虽非运行时数据区,但不可忽视
直接内存(Direct Memory)不属于 JVM 规范定义的运行时数据区,但它被 NIO 等组件频繁使用,通过 java.nio.ByteBuffer.allocateDirect() 分配,绕过堆直接向操作系统申请内存。它的大小不受 -Xmx 限制,但受限于本机总内存;若过度使用,可能引发系统级内存不足,导致 OOM。
各区域与常见问题的关联
不同内存区域对应不同类型的运行时异常,定位问题时可快速缩小范围:
- java.lang.OutOfMemoryError: Java heap space → 堆内存不足,关注对象泄漏或堆大小配置(-Xms/-Xmx)
- java.lang.OutOfMemoryError: Metaspace → 元空间耗尽,常见于大量动态生成类(如某些 ORM、热部署框架)
- java.lang.StackOverflowError → 虚拟机栈或本地方法栈溢出,多因递归过深或线程栈过大(-Xss 设置过高)
- java.lang.OutOfMemoryError: Direct buffer memory → 直接内存超限,需检查 ByteBuffer 使用及 -XX:MaxDirectMemorySize 设置

















