JVM运行时栈帧结构
本文探讨JVM运行时的执行字节码的时候的数据结构、方法调用等。
栈帧
栈帧是方法对应JVM中的数据结构,他描述了一个方法的具体内容。每一个方法的调用都对应着栈帧在虚拟机栈的压栈和出栈的过程。可想而知,栈帧是线程私有的。
局部变量表
用于存放方法参数和方法内部定义的局部变量。局部变量表的容量以变量槽为最小单位。
变量槽
一个变量槽可以存储一个32位以内的数据结构,(boolean、cyte、char、shot、int、float、reference、returnAddress)
-
reference(对象引用):①找到堆中数据存放的起始地址或索引,②找到对象所属类型在方法区中的类型信息。
-
returnAddress:为字节
码指令jsr、jsr_w和ret服务的,指向了一条字节码指令的地址。
JVM通过索引定位法访问变量槽,也就是从0开始而不是通过内存地址或引用去访问。由于一个变量槽的大小是32位,所以访问32位以内的数据访问N就是第N个变量槽。那么大于32位呢,如double和long,则使用相邻的两个变量槽存储,JVM不允许只访问这两个中的某一个。
操作数栈
在执行方法的过程中,后不断的将数据入栈出栈进行计算。
动态连接
在class中,有常量池,常量池中有很多符号引用。
在最初就能将符号引用转换成直接引用的情况叫做静态引用,每次运行期间都传化成直接引用叫做动态连接。
方法调用
方法调用不是执行方法,而是确定调用的是哪个方法。
在Class
文件中,只有常量池中的符号引用,在加载类的过程中,有些确定的情况可以在【解析】的时候被解析成直接引用,他们分别为 【静态方法】【实例构造器】【私有方法】【父类方法】【被final修饰的方法】他们统称为非虚方法。其他方法成为虚方法。
虚方法的解析过程在《深入理解java虚拟机》中称为分派(Dispatch),分为静态分派和动态分派两张。
- 静态分派:在编译器行为,编译器将能够确定下来的符号引用转成直接引用。金典实现:重载
- 动态分派:在运行期根据实际类型确定方法执行版本的分派过程称为动态分派。金典实现:重写
方法返回地址
执行引擎遇到方法返回的字节码指令时会正常返回,发生异常时会异常返回。
方法返回就相当于将当前栈帧出栈,因为一个方法的执行对应的是一个当前栈帧。在返回后 恢复上层方法的
局部变量表和操作数栈,把返回值(如果有的话)压入调用者栈帧的操作数栈中,调整PC计数器的值
以指向方法调用指令后面的一条指令等。