局部变量表和操作数栈是栈帧中分工协作的两个核心结构:前者为编译期确定的索引数组,存储参数与局部变量(this在index 0,long/double占两槽,槽可复用);后者为运行时LIFO栈,支撑字节码运算(如iload加载、iadd计算、istore存储),二者协同完成指令执行。

局部变量表和操作数栈是每个栈帧里最核心的两个结构,它们不互相替代,而是分工协作:一个管“存哪儿”,一个管“怎么算”。
局部变量表:方法数据的静态索引表
它是一块编译期就定好大小的数组,按槽位(slot)编号从 0 开始存放数据。this 引用固定在 index 0;参数从 index 1 起顺序排列;之后才是方法体内声明的局部变量。
- int、boolean、short、char、byte、float、double、reference 都占 slot,但 long 和 double 占两个连续 slot
- 槽位可复用——变量作用域结束,对应 slot 就能被后续变量覆盖,所以嵌套代码块不会让表变大
- 它本身不参与运算,只是提供入口:字节码指令如 iload_2 表示“把 index=2 的值取出来,压进操作数栈”
- 局部变量不会自动初始化,JVM 只分配槽位,不填默认值;这和堆里的成员变量有本质区别
操作数栈:运行时的临时演算纸
它是一个后进先出(LIFO)的栈,深度在编译时记在 Code 属性的 max_stack 字段里,JVM 据此预分配空间。所有计算都在这里发生,没有索引,只有栈顶和栈底。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 常量加载(iconst_5)、变量读取(iload_1)、算术运算(iadd)、方法调用(invokestatic)等都依赖它
- 方法调用前,参数按从左到右顺序依次压栈;调用后,返回值也先进入操作数栈,再由后续指令(如 istore_3)存回局部变量表
- 比如执行 int a = b + c; 时:先 iload_1(b 入栈),再 iload_2(c 入栈),接着 iadd(弹出两数相加,结果压栈),最后 istore_3(把栈顶结果存到局部变量表 index=3)
二者配合:一次字节码执行的完整闭环
以 factorial(5) 中的 n * factorial(n-1) 这一行为例:
立即学习“Java免费学习笔记(深入)”;
- iload_0 把参数 n(index=0)加载到操作数栈
- iconst_1 和 isub 计算出 n−1,并留在栈顶
- invokestatic 触发递归调用,此时操作数栈顶的 n−1 作为实参传入新栈帧
- 递归返回后,原栈帧的操作数栈里已有 factorial(n−1) 的结果,再 iload_0 重新载入原始 n,最后 imul 完成乘法
整个过程里,局部变量表像座位图,标明数据在哪;操作数栈像草稿纸,所有中间步骤都在上面实时展开。JVM 执行引擎只操作当前栈帧的这两个结构,不直接触碰堆或方法区。

















