Java中变量是存储在堆中还是栈中?
Java中变量是存储在堆中还是栈中?
月伴飞鱼变量存放位置的判断依据
Java运行时内存主要分为:
栈(Stack):线程私有,存放方法调用相关数据。
堆(Heap):线程共享,存放对象实例。
方法区 / 元空间(Method Area / Metaspace):存放类元信息、常量池、静态变量。
判断依据:
基本类型的值(除
String
这种引用类型外)。
- 如果是方法的局部变量 → 存在栈帧的局部变量表
- 如果是对象的成员变量 → 存在对象实例中(堆里)
引用类型变量
- 引用本身(指向对象的地址)存放在栈帧局部变量表或对象实例中。
- 对象本体存放在堆中。
类的元数据、常量池、静态变量 → 方法区 / 元空间。
方法内局部变量的存放位置
示例:
1 | public void test() { |
分析:
num
:基本类型的局部变量 → 栈。
str
:引用在栈,字符串常量存方法区。
user
:引用在栈,对象实例在堆。
特殊情况:逃逸分析与栈上分配
JIT 编译优化时,如果对象不会逃出当前方法(没有被其他线程或方法引用),JVM 可将对象分配在栈上或进行标量替换。
优势:减少 GC 压力。
开启方式(JDK 8 默认开启):
1 | -XX:+DoEscapeAnalysis |
总结表
类型 | 场景 | 存放位置 |
---|---|---|
基本类型局部变量 | 方法内声明 | 栈 |
基本类型成员变量 | 对象属性 | 堆(跟随对象) |
引用类型局部变量 | 方法内声明 | 引用在栈,对象在堆 |
引用类型成员变量 | 对象属性 | 引用和值都在堆(对象内部) |
静态变量 | 类加载时 | 方法区 / 元空间 |
常量 | 编译期常量池 / 运行时常量池 | 方法区 / 元空间 |