运行时栈帧结构

来源:互联网 发布:黄金烤鸡腿堡 知乎 编辑:程序博客网 时间:2024/06/17 11:19

概述

  栈帧用于支持虚拟机进行方法调用和方法执行的数据结构,是虚拟机栈的栈元素,存储了方法的局部变量表、操作数栈、动态链接和方法返回地址等信息。每一个方法从调用开始至执行完成的过程,都对应着一个栈帧在虚拟机栈里面从入栈到出栈的过程。
  在编译代码的时候,栈帧中需要多大的局部变量表,多深的操作数栈都已经操作数栈都已经完全确定,并且写入到方法表的Code属性之中,因此一个栈帧需要分配多少内存,不会受到程序运行期变量数据的影响,而仅仅取决于具体的虚拟机实现。
  

局部变量表

  用于存放方法参数和方法内部定义的局变量,Class文件中方法的Code属性的max_locals确定了该方法所需要分配的局部变量表的最大容量。局部变量表的容量以变量槽(Variable Slot)为最小单位,虚拟机规范中并没有明确指明一个Slot应占用的内存空间大小,只是规定一个Slot应该能存放一个boolean、byte、char、short、int、float、reference或returnAddress类型的数据
  对于64位的数据类型,虚拟机会以高位对齐的方式为其分配两个连续的Slot空间。
  虚拟机通过索引定位(类似数组)的方式使用局部变量表。
  如果执行的是实例方法(非static),那局部变量表中第0个索引的Slot默认适用于传递方法所属独享实例的引用,在方法中可以通过关键字“this”来访问这个隐含的参数。

操作数栈

  操作数栈为后入先出栈,它的最大射弩在编译的时候已经写入到Code属性的max_stacks数据项中。操作数栈的每一个元素可以说任意的Java数据类型,32位数据类型所占栈容量为1,64位数据类型所占的栈容量为2。
  Java虚拟机的解释执行引擎称为“基于栈的执行引擎”,其中所指的“栈”就是操作数栈。

动态连接

  每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接(Dynamic Linking)。我们知道Class文件的常量池中存有大量的符号引用,字节码中的方法调用指令就以常量池中指向方法的符号引用作为参数。这些符号引用一部分会在类加载阶段或者第一次使用的时候就转化为直接引用,这种转化称为静态解析。另外一部分将在每一次运行期间转化为直接引用,这部分称为动态连接。

方法返回地址

  方法有两种退出方式:return,或者是抛出异常未被捕获。
  无论以何种方式退出,都需要返回到方法被调用的位置,程序才能继续执行。方法返回时可能需要在栈帧中保存一些信息,用来帮助恢复它的上层方法的执行状态。一般来说,方法正常退出时,调用者PC计数器的值就可以作为返回地址,栈帧中很可能会保存这个计数器值。