jvm内存结构按运行时角色和线程可见性划分为堆(线程共享,存对象实例和数组)、虚拟机栈(线程私有,存栈帧及局部变量表、操作数栈等)、方法区/元空间(线程共享,存类信息、静态变量、常量池)、程序计数器和本地方法栈(线程私有,辅助执行)。

JVM 内存结构不是按“数据类型”(比如 int、String)直接分类存放的,而是按运行时角色和线程可见性划分区域,不同类型的数据依据其生命周期、作用域和访问方式,被自动分配到对应区域。理解这个逻辑,才能避免常见误用(比如误以为“String对象存在栈里”)。
堆:所有对象实例和数组的唯一归属地
堆是线程共享区域,也是 JVM 中最大的一块内存。只要通过 new 创建的对象(包括 String 字面量对应的字符串对象、ArrayList、自定义类实例等),以及所有数组(无论基本类型还是引用类型数组),都必须分配在堆中。
- 局部变量中的 引用(如
String s = new String("abc");中的s)本身不存对象,只存堆中对象的地址,这个引用变量放在栈帧的局部变量表里 - 对象的字段(成员变量)也随对象一起存在堆中;静态变量(
static)则存于方法区(JDK 8+ 是元空间) - 堆是垃圾回收的主要场所,对象是否可达、何时回收,均由 GC 算法管理
虚拟机栈:方法执行与局部变量的私有空间
每个线程启动时都会创建一个虚拟机栈,它由一个个栈帧组成,每个栈帧对应一次方法调用。这里存放的是方法执行所需的数据容器,不是“数据本身”的长期住所。
- 局部变量表保存:8 种基本类型值(int、boolean 等)、对象引用(4 字节或 8 字节地址)、returnAddress 类型
- 操作数栈用于字节码指令计算,比如
iadd、invokevirtual的中间运算过程 - 栈帧随方法调用而入栈,方法返回即出栈;栈深度超限会抛
StackOverflowError
方法区(元空间):类元信息与静态数据的集中营
方法区是线程共享区域,存储已被虚拟机加载的类信息、常量池、静态变量、即时编译后的代码等。JDK 8 起,永久代被移除,取而代之的是使用本地内存的元空间(Metaspace)。
- 类的
static final基本类型常量(如public static final int MAX = 100;)在编译期就进入常量池,运行时直接内联,不占堆 -
static变量(非 final 或引用类型)的值仍存于方法区,但其所引用的对象(如static List<string> list = new ArrayList();</string>)本身在堆中 - 字符串常量池(
"hello")在 JDK 7+ 已从方法区移到堆中;但类加载阶段解析的符号引用、运行时常量池结构仍在方法区
程序计数器与本地方法栈:辅助执行的轻量级区域
这两块区域几乎不参与“数据存放”的决策,但对执行逻辑至关重要:
- 程序计数器:每个线程独有,仅记录当前线程正在执行的字节码指令地址;是线程切换后能恢复执行位置的基础,不会溢出
- 本地方法栈:为 JNI 调用的 native 方法服务,结构类似虚拟机栈,但面向 C/C++ 等本地代码;Java 应用层开发中极少需主动干预
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











