虚拟机字节码执行引擎——运行时栈帧结构
文章目录
虚拟机与物理机异同
同:都具有代码执行能力
异:物理机的执行引擎是建立在处理器、硬件、指令集和操作系统上面的;而虚拟机的执行引擎是自己实现的,因此可以自行制定指令集。
栈帧
栈帧存储了方法的局部变量表、操作数栈、动态连接、方法返回地址等信息。每一次方法的调用和完成都对应一个栈帧的入栈和出栈。
在编译代码阶段,栈帧里面的局部变量表需要多大内存空间是已经确定了的。
栈帧的结构
一、局部变量表
局部变量表
是一组变量值存储空间,用来存放方法参数和方法内部定义的局部变量。
局部变量表容量的最小单元
局部变量表以变量槽(variable slot)为最小单元。变量槽的大小,java虚拟机规范没有明确指出。只要能存放boolean、byte、char、short、int、float、reference、returnAddress类型的数据就行(小于等于32位)。
Java虚拟机的数据类型
前6种就不用说了。至于reference只要能够满足两点:
- 通过引用(reference)可以直接或间接的获取对象在堆中的起始地址
- 通过引用可以直接或间接的获取对象的所属类型信息(在方法区)
就行。而returnAddress现在不怎么使用了。
64位数据类型long、double
对于64位的数据类型,虚拟机是分配两个连续的slot来存储的。不能单独的访问其中任何一个slot,只能一起访问。
局部变量表的结构
先是this,然后参数列表,然后局部变量
原文是这样说的:
slot的重用
为了节省栈帧空间,slot是可以重用的。在方法体内定义的变量,其作用域不一定覆盖整个方法体,如果当前PC计数器的值超过了某个变量的作用域,那么该变量的slot就可以让其他变量使用了。需要注意的时,Slot复用可能会直接影响垃圾收集行为。
二、操作数栈
操作数栈所需空间大小在编译阶段就确定了。
在概念模型中,栈桢是相互独立的。但在大多数虚拟机中都进行了优化,将两各栈桢打一部分重叠起来。如下所示:
三、动态连接
每一个栈桢都存放了一个指向运行时常量池中该栈桢所属方法的引用,这样是为了进行动态连接。这个符号引用存放在栈桢的动态连接中。
静态解析:就是在类加载阶段就进行符号引用解析。
动态连接:就是在程序运行期间就才将符号引用解析为直接引用
四、方法返回地址
方法的退出有两种方式,无论那种方式,都会返回到方法调用位置。
- 正常完成出口:方法正常完成。正常退出,方法返回地址大多数很可能存放在程序计数器中。
- 异常完成出口:方法内部发生异常,并以异常并没有得到处理。方法打返回地址是由异常处理表确定的。
五、附加信息
《虚拟机规范》允许虚拟机的具体实现将一些没有规定的信息存到栈桢中去,我们称为附加信息。我们把动态连接、方法返回地址、附加信息一同叫做栈桢信息。