一、概述
执行引擎在执行java代码的时候可能会有解释执行和编译执行;
输入字节码文件,处理过程是字节码解析的等效过程,输出的是执行结果。
二、运行时栈帧结构
栈帧:用于支持虚拟机进行方法调用和方法执行的数据结构;它是虚拟机运行时数据区中的虚拟机栈的栈元素;栈帧存储了方法的局部变量、操作数栈、动态链接和方法返回地址等信息。
对于执行引擎来说,在活动线程中,只有位于栈顶的栈帧才是有效的称为当前栈帧,与这个栈帧相关的方法称为当前方法。
1、局部变量表
用于存放方法参数和方法内部定义的局部变量;容量以变量槽为最小单位,没个slot都应该可以存放一个Boolean、byte、char、short、int、float、reference和returnAddress类型的数据;
虚拟机使用索引定位的方式使用局部变量表;
在方法执行时,虚拟机是使用局部变量表完成参数值到参数变量列表的传递过程。如果当前字节码的pc计数器的值已经超过了某个变量的作用域,那这个变量对应的slot就可以交给其他变量使用;
2、操作数栈
先入后出栈。
当一个方法刚刚开始执行的时候,这个方法的操作数栈是空的,在方法的执行过程中,会有各种字节码指令往操作数栈中写入和提取内容,即出栈/入栈操作。
3、动态连接
每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用。
4、方法返回地址
正常完成出口、异常完成出口。一般来说,方法正常退出时,调用者的pc计数器的值可以作为返回地址,栈帧中可能会保存这个计数器值。而方法异常退出时,返回的地址要通过异常处理表确定,栈帧中一般不会保存这部分信息。
方法退出的过程实际上等同于把当前栈帧出栈,因此退出时可能执行的操作有:恢复上层方法的局部变量表和操作数栈,把返回值压入调用者栈帧的操作数中,调整pc计数器的值以指向方法调用指令后边的一条指令。
5、附加信息
三、方法调用
确定被调用方法的版本。一切方法调用在class文件里边存储的都是符号引用,而不是方法在实际运行时内存布局中的入口。
java虚拟机中提供的5条方法调用字节码指令:
invokestatic:调用静态方法
invokespecial:调用实例构造器<init>方法、私有方法和父类方法
invokeirtual:调用所有的虚方法
invokeinterface:调用接口方法
invokedynamic:先在运行时动态解析出调用点限定符所引用的方法,然后再执行该方法
1、解析调用
在类加载的解析阶段,会将一部分符号引用转换为直接引用。解析成立的前提:编译期可知,运行期不可变。只要能被invokestatic和invokespecial指令调用的方法,都可以在解析阶段确定唯一的版本;符合这个条件的有静态方法、私有方法、实例构造器、父类方法;
2、分派调用
1>静态分派(重载通过参数的静态类型判断)
静态类型:变化仅在使用时发生,变量本身的静态类型不会改变,并且最终的静态类型是在编译期可知的;
实际类型:变化结构在运行期时才可以确定,编译器在编译程序的时候并不知道一个对象的实际类型是什么;
2>动态分派(重写)
invokevirtual指令的多态查找:
找到操作数栈顶的第一的元素指向的对象的实际类型,记作c(运行期确定接收者的实际类型);
如果在类型c中找到与产量中的描述符合简单名称都相符的方法,则进行访问权限校验,如果通过,则返回这个方法的直接引用,查找结束;如果不通过,返回异常;
否则按照继承关系从下往上依次对c的各个父类进行上一步的搜索和验证;如果始终没有找到合适的方法,抛出异常;
3>单分派和多分派
方法的接收者与方法的参数统称为方法的宗量;
静态分派属于多分派;动态分派属于单分派类型;
四、基于栈的字节码解释执行引擎
1、解释执行
2、基于栈的指令集与基于寄存器的指令集
3、基于栈的解释器执行过程
网友评论