Java虚拟机栈中每个方法调用对应一个栈帧,局部变量表是其固定大小的组成部分,编译期确定、运行期不可扩容;压栈时分配Slot空间,出栈时整体释放。

Java虚拟机栈中,每个方法调用对应一个栈帧(Stack Frame),而栈帧的压栈与出栈,本质上是方法执行生命周期在内存中的映射;局部变量表是栈帧的一部分,用于存放方法参数、内部变量等,它的结构在编译期就已确定,大小固定,不随运行时变化。
压栈:方法调用时创建新栈帧并初始化局部变量表
当线程执行到某个方法调用(如 invokestatic 或 invokevirtual)时,JVM 会在当前线程的虚拟机栈顶部压入一个新的栈帧。这个过程包括:
- 根据该方法的字节码,计算所需栈帧空间(含局部变量表、操作数栈、动态连接、方法返回地址等)
- 为局部变量表分配连续内存空间,大小由编译器在生成 class 文件时写入方法的 Code 属性 中(max_locals 字段)
- 局部变量表以变量槽(Slot)为单位,每个 Slot 宽 32 位;long/double 占两个 Slot,其余类型(int、reference、boolean 等)占一个
- 方法参数从索引 0 开始存放(静态方法从 0 起,实例方法第 0 个 Slot 存放 this 引用)
出栈:方法执行结束时栈帧被移除,局部变量表自动失效
当方法正常返回(return 指令)或异常抛出且未被捕获时,当前栈帧从虚拟机栈顶弹出,其占用的所有内存(包括局部变量表、操作数栈等)立即释放:
- 局部变量表中存储的变量引用会消失,若这些引用是对象的唯一强引用,则对应对象可能被 GC 回收
- 出栈后,上层调用方法的栈帧重新成为栈顶,程序计数器跳转回调用点的下一条指令
- 注意:局部变量表本身不存储对象实例,只存基本类型值或对象引用(即指向堆中对象的指针)
局部变量表不是“运行时动态扩容”的变量容器
容易误解的是:把局部变量表当成类似 Java 中 ArrayList 那样的动态结构。实际上:
立即学习“Java免费学习笔记(深入)”;
- 它的大小在类加载的解析阶段就已确定,运行期不会改变
- 代码中看似“新增”变量(如 if 块内声明 int x = 1),只是复用已有 Slot(比如用同一个索引 1 的 Slot),并非扩展表长度
- 不同作用域的局部变量可以共享 Slot:方法执行完一个代码块后,该块内变量占用的 Slot 可被后续变量复用
一个简单例子帮你看清压栈/出栈与局部变量表的关系
假设有如下方法:
public static void main(String[] args) {
int a = 10;
String s = "hello";
foo(a, s);
}
static void foo(int x, String y) {
int b = x + 1;
System.out.println(y + b);
}
执行过程简述:
- main 方法调用 → 压入 main 栈帧,局部变量表:args(Slot 0)、a(Slot 1)、s(Slot 2)
- 调用 foo → 压入 foo 栈帧,局部变量表:x(Slot 0)、y(Slot 1)、b(Slot 2)
- foo 执行完毕 → foo 栈帧出栈,其局部变量表整体释放
- 回到 main,继续执行下一条指令(如果有的话)


















