栈帧是jvm方法执行的上下文单元,包含局部变量表(存参数和局部变量,按slot分配,this占第0槽)、操作数栈、动态链接和返回地址;每个方法调用对应一个栈帧入栈,返回则出栈,线程私有且遵循lifo。

JVM 虚拟机栈通过栈帧(Stack Frame)来组织方法执行的上下文,而局部变量就存放在每个栈帧内部的局部变量表中。栈帧本身是虚拟机栈的存储单位,一个方法调用对应一个栈帧入栈,方法返回则该栈帧出栈。
局部变量表:按槽(Slot)分配,类型决定占用空间
局部变量表是一组连续的变量槽(Slot),每个槽大小固定为 32 位。它用于存放:
- 方法参数(含隐式的 this 引用,非静态方法第 0 号槽)
- 方法内部定义的局部变量(如
int i = 1;、String s = "abc";) - 基本类型(
boolean、byte、char、short、int、float)各占 1 个 Slot -
long和double占 2 个连续 Slot(因 64 位宽度) - 对象引用(
reference)占 1 个 Slot,实际指向堆中对象实例
注意:局部变量表的大小在编译期就确定(由字节码中 max_locals 指令指定),与运行时变量是否“还活着”无关;但作用域结束后,其 Slot 可被后续变量复用。
栈帧结构:不只是局部变量,还有三大核心区域
每个栈帧包含以下关键部分,共同支撑方法执行:
- 局部变量表:已说明,承载参数和显式声明的变量
-
操作数栈:后进先出的临时数据区,字节码指令(如
iadd、iload)在此压栈/出栈完成计算 - 动态链接:保存指向运行时常量池的引用,支持方法调用时符号引用转为直接引用(如多态分派)
- 方法返回地址:记录方法正常 return 或异常退出后,要跳回的调用者字节码位置
这些内容共同构成一个完整的方法执行上下文,且仅对当前线程可见 —— 栈帧始终绑定线程私有栈,不共享、不跨线程。
栈帧如何进出虚拟机栈:严格遵循 LIFO
线程执行过程就是栈帧不断压入与弹出的过程:
- 线程启动时,JVM 为其分配独立虚拟机栈;main 方法调用 → 创建 main 栈帧并入栈
- main 中调用
foo()→ 新建 foo 栈帧,压入栈顶,成为当前帧 - foo 中再调用
bar()→ bar 栈帧入栈,覆盖为当前帧 - bar 执行完毕 → bar 栈帧弹出,控制权交还 foo 帧,foo 继续执行剩余指令
- 所有方法返回后,栈变为空,线程终止,整个虚拟机栈被回收
整个过程无需 GC 干预,但若递归过深或方法嵌套太多,可能导致栈空间耗尽,抛出 StackOverflowError。











