在Java虚拟机规范中制定了虚拟机字节码执行引擎的概念模型,这个概念模型成为各种虚拟机执行引擎的统一外观.在不同的虚拟机实现里,执行引擎在执行java代码时可能会有解释执行和编译执行两种选择,也有可能两者兼备.
但所有的执行引擎的外观都是一样的:输入的是字节码文件,处理过程是字节码解析的等效过程,输出的是执行结果.
本章先讲解用于支持虚拟机进行方法调用和方法执行的数据结构:栈帧
栈帧存储了方法的局部变量表,操作数栈,动态连接,方法返回地址等信息.每一个方法从调用开始到执行完成的过程,都对应着一个栈帧在虚拟机栈里面从入栈到出栈的过程.
对于执行引擎来说,在活动线程中,只有位于栈顶的栈帧才是有效的,称为当前栈帧.与这个栈帧关联的方法是当前方法.执行引擎执行的所有字节码指令都只针对当前栈帧进行操作.
1,局部变量表:用于存放方法参数和局部变量
局部变量表的容量以变量槽(Slot)为最小单位,一个Slot能存放32位以内的数据类型,对于64位的数据类型,虚拟机会以高位对齐的方式为其分配两个连续的Slot空间.
虚拟机是使用局部变量表完成参数值到参数变量列表的传递过程,如果是实例方法(非static)那么局部变量表中第0位索引的slot默认是用于传递方法所属对象实例的引用,方法中可以通过this来访问这个隐含的参数。其余参数则按照参数表的顺序来排列,占用从1开始的局部变量slot,参数表分配完毕之后,再根据方法体内部定义的变量顺序和作用域分配其余的slot。 注:类变量有两次赋值的过程,一次在准备阶段,赋予系统初始值(比如int默认值为0,boolean默认值为false,object类型默认值为null等),另外一次在初始化阶段,赋予程序员定义的初始值。因此即使在初始化阶段程序员没有为类变量赋值也没用关系,类变量仍然具有一个确定的初始值。但是局部变量若是定义了但没有赋初始值是没法使用的,类加载将会失败。2,操作数栈(LIFO)
在方法执行过程中,会有各种字节码指令往操作数栈写入和提取内容.
3,动态连接
每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接。我们知道class文件的常量池中存有大量的符号引用,字节码中的方法调用指令就以常量池中指向方法的符号引用为参数。这些符号引用一部分会在类加载阶段或第一次使用的时候转化为直接引用,这种转化为称为静态解析,另外一部分将在每一次的运行期间转化为直接引用,这部分称为动态连接。
4,方法返回地址:一个方法执行后,有两种方法退出这个方法
一是正常退出,执行引擎遇到任意一个返回的字节码指令.这是可能会有返回值传递给上层调用者.返回指令也可能没有返回值.
二是异常退出,执行过程中遇到异常,并且这个异常没有在方法体内的到处理,无论是Java虚拟机内部产生的异常,还是代码中athrow字节码指令产生的异常,只要在本方法的异常表中没有搜索到匹配的异常处理器,就会导致方法退出.