掌握 JVM 运行时划分的五种核心内存区域
理解每个区域的用途、生命周期与线程共享特性
能够区分堆、栈、方法区等关键区域的存储内容
了解 Metaspace 对传统方法区的演进意义
Java 虚拟机(JVM)在执行 Java 程序时,将内存划分为 五个主要运行时数据区。这些区域协同工作,支撑类加载、对象创建、方法调用和线程执行等核心功能。

核心作用
存储 类级别的结构信息,包括:
类的字节码(Bytecode)
方法和字段的元数据
静态变量(static 字段)
运行时常量池(Runtime Constant Pool)
接口与注解信息
演进:从 PermGen 到 Metaspace
Java 7 及之前:方法区由 永久代(PermGen) 实现,位于 Java 堆内。
Java 8 起:永久代被移除,改用 Metaspace(元空间),使用 本地内存(Native Memory),不再受 -Xmx 堆大小限制。
优势:避免
java.lang.OutOfMemoryError: PermGen space,提升类加载灵活性。
注意:虽然静态变量本身存储在 Metaspace,但如果其值是对象引用(如
static List list = new ArrayList<>()),对象实例仍分配在堆中,Metaspace 仅保存引用。
核心作用
唯一存放对象实例和数组的地方
所有通过 new 创建的对象均在此分配内存
是 垃圾回收(GC)的主要区域
特性
线程共享:所有线程均可访问堆中的对象(需同步控制)
动态分配:内存大小可在运行时调整(通过 -Xms / -Xmx)
分代管理:通常分为新生代(Young Gen)和老年代(Old Gen)
示例
String s = new String("Hello"); // "Hello" 对象 → 堆;s 引用 → 栈
int[] arr = new int[10]; // 数组对象 → 堆核心作用
支撑 方法调用与返回 的执行模型
每个方法调用对应一个 栈帧(Stack Frame)
栈帧包含
局部变量表(Local Variables)
操作数栈(Operand Stack)
动态链接(指向运行时常量池的方法引用)
方法返回地址
特性
线程私有:每个线程启动时创建独立栈
自动管理:方法执行结束,栈帧自动出栈释放
LIFO 结构:后进先出,高效内存管理
局部基本类型变量(如
int,boolean)直接存储在栈中;对象引用也存于栈,但对象本身在堆。
核心作用
记录 当前线程正在执行的 JVM 字节码指令地址
是线程切换后能恢复执行的关键
特性
线程私有:每个线程拥有独立 PC 寄存器
最小内存区域:仅存储一个地址值
唯一不会发生 OOM 的区域
对于 native 方法,PC 值未定义(因不由 JVM 解释执行)。
核心作用
支持 native 方法(非 Java 编写,如 C/C++)的调用
存储 native 方法的调用状态与参数
特性
线程私有
具体实现由 JVM 厂商决定(可能与 JVM 栈合并)
也称为 “C 栈”
常用于 JNI(Java Native Interface)场景,如调用操作系统 API 或高性能计算库。
为什么程序计数器是唯一不会发生 OutOfMemoryError 的内存区域?
在多线程环境下,如果多个线程同时访问同一个堆中的对象,JVM 如何保证内存可见性与一致性?
Metaspace 使用本地内存而非 Java 堆,这对系统整体内存管理和容器化部署(如 Docker)有何影响?