栈帧的内部结构
局部变量表
- 定义为一个数字数组,主要用于存储方法的参数和定义在定义在方法体内的局部变量,这些数据类型主要有基本数据类型,对象的引用,以及returnAddress类型
- 由于局部变量表是建立在线程的栈上,是线程私有的数据,因此不存在数据安全问题
- 局部变量表的大小是在编译器确定下来的,并且保存在Code属性的maxinum local variables数据项中,在方法运行期间是不会改变局部变量表的大小的
- 参数的存放总是在局部变量数组的index0开始到数组长度-2的索引结束
- 局部变量表最基本的存储单元是Slot(变量槽)
- 如果当前帧是由构造方法或者实例方法创建的,那么该对象引用this将会放在index为0的solt处,其余参数按照参数表顺序排列
- 局部变量表也是重要的垃圾回收根节点,只要在局部比那量表中直接或间接引用的对象都不会被回收
操作数栈(表达式栈)
-
主要用于保存计算过程的结果,同时作为计算过程中变量的临时储存空间
-
操作数栈就是jvm执行引擎的一个工作区,当一个方法开始执行的时候,一个新的栈帧也会随之被创建出来,这个方法的操作数栈是空的
-
每一个操作数栈都会拥有一个明确的栈深度用于储存数值,其所需要的最大深度在编译时就定义好了,保存在方法的Code属性中名为max-stack的值
-
栈中任何一个元素都可以是Java 中任意数据类型
-
32bit的占用一个栈深度
-
64bit的占两个
操作数栈并非采用访问索引的方式来进行访问的,而是通过出栈和入栈的方式来完成的
-
-
如果被调用的方法带有返回值的话,其返回值将会被压入当前栈帧的操作数栈中,并更新PC寄存器中下一条需要执行的字节码指令
-
操作数栈中的元素类型必须与字节码指令严格匹配,这由编译器在编译期间进行验证,同时在类加载过程中的类型检验的数据分析阶段需要再次验证
动态链接(指向运行时常量池的方法引用)
-
方法的返回地址
-
存放该方法的pc寄存器的值
-
一个方法的结束,有两种方式
- 正常执行完成
- 出现未处理的异常,非正常退出
-
无论是通过哪种方法退出,在方法推出后都要返回到方法被调用的位置,方法非正常退出时,调用着的pc计数器的值作为返回地址,即调用该方法指令的下一条指令的地址,而通过一场退出的,返回地址是要通过异常表来确定,栈帧中一般不会保存这部分信息
-
-
一些附加 的信息