虚拟机栈是线程独享的执行引擎底座,以栈帧为单位管理方法生命周期,遵循lifo原则;栈帧含局部变量表(编译期定长)、操作数栈(字节码运算)、动态链接与返回地址(支撑调用跳转)。

虚拟机栈是 Java 线程运行的“执行引擎底座”,它的核心不是堆那样的共享内存,而是每个线程独享的一块轻量级内存空间。它不负责对象存储,只专注方法调用的生命周期管理——靠的就是一个个结构清晰、职责分明的栈帧。
栈帧是方法执行的最小单位
每次方法调用,JVM 就同步创建一个栈帧压入当前线程的虚拟机栈;方法执行结束(无论正常 return 还是异常抛出),该栈帧就立即弹出。整个过程严格遵循后进先出(LIFO)原则,栈顶的栈帧永远是“当前栈帧”,只有它能被字节码执行引擎直接操作。
- 一个线程从 main() 开始,每调一层方法就新增一个栈帧,深度随调用链增长
- 栈帧的生命周期与方法调用完全绑定,不依赖 GC,也不参与对象回收
- 栈空间大小可通过 -Xss 参数设置,过深递归或过多嵌套易触发 StackOverflowError
局部变量表:编译期定长的“参数+变量”容器
它位于栈帧起始处,是一组以“槽(Slot)”为单位的数组,用于存放方法参数和内部定义的局部变量。关键点在于:大小在编译时就已确定,运行期不可扩展。
- 基本类型(int、char 等)占 1 个 Slot;long 和 double 占 2 个 Slot
- 引用类型(如 Object obj)存的是对象在堆中的地址,不是对象本身
- Slot 编号从 0 开始:第 0 位通常是 this(非 static 方法),后续依次是形参、局部变量
操作数栈:字节码指令的“临时计算器”
它是一个后进先出的栈结构,用于支撑字节码运算——比如 iload、iadd、istore 等指令都围绕它读写数据。你可以把它理解成 CPU 的寄存器在 JVM 层的模拟。
- 方法开始时为空,指令逐步将值压入;计算时弹出操作数,结果再压回
- 栈深度也在编译期写入方法 Code 属性,运行中不会动态调整
- 例如
return a + b:先 iload_0、iload_1 压入 a 和 b,再 iadd 计算并压入结果,最后 ireturn 弹出返回
动态链接与返回地址:支撑方法跳转与上下文恢复
这部分保障了方法调用的连贯性和可追溯性。
- 动态链接:指向运行时常量池中该方法的符号引用,支持多态调用(如 invokevirtual)时的运行时解析
- 方法返回地址:记录调用者方法下一条指令的位置,确保方法退出后能准确回到原执行点
- 返回分两种:正常完成(return 指令)传递返回值;异常完成(未捕获异常)则不传值,直接销毁栈帧











