APP下载

字节码执行引擎

消息来源:baojiabao.com 作者: 发布时间:2024-05-08

报价宝综合消息字节码执行引擎

在上一篇我们介绍了类载入器的相关功能,在这一篇中我们在分享一下虚拟机器中的另一个非常重要的功能字节码执行引擎。我们知道Java虚拟机器的主要任务就是载入class档案并执行其中的字节码。载入class的功能是由类载入器实现的,那么执行其中字节码的功能就是由字节码执行引擎执行的。下图为虚拟机器的基本结构图。

虚拟机器的执行引擎有很多种,不同的执行引擎也有很大的差别,它们主要的区别如下:

最简单的执行引擎是一次性解释字节码。另一种执行引擎叫做即使编译器,但会很消耗内存。执行引擎会把第一次执行的字节码编译成本地机器程式码,本地机器程式码会被快取,当方法第二次呼叫时可以直接使用快取中的本地机器程式码,提高程式的执行效率。还有一种执行引擎叫自适应优化器 。虚拟机器执行字节码时,会监视程式中使用最频繁的程式码,将其编译成本地机器程式码,而其它的字节码,继续保留为字节码。这样当程式频繁呼叫已经编译成本地机器程式码时,会提高程式的执行效率,但由于没有将所有的字节码都编译成本地机器程式码,所以这种方式的执行引擎占用的内存相比即使编译器要小。执行引擎是由硬件芯片构成,它用原生代码执行字节码。上面所说的都是不同执行引擎的的执行特性,但无论是哪一种执行引擎其中最基本的功能都是执行字节码。下面我们来看一下在执行引擎内部是怎么保证字节码的正确执行的。

栈帧栈帧是虚拟机器进行方法呼叫和方法执行的资料结构。栈帧储存了方法的区域性变量表、 算子栈、 动态连线和方法返回地址等资讯。每一个方法从呼叫开始到执行结束,在虚拟机器内部的过程就是栈帧在栈里面从入栈到出栈的过程。在虚拟机器中栈是针对执行绪来操作的,也就是说每一个执行绪都有一个独立的栈内存。如果执行绪中的方法呼叫链很长,并且很多方法都同时在执行。那么虚拟机器怎么保证方法的正常呼叫呢?

其实对于执行引擎来说,在活动的执行绪中,只有位于栈顶的栈帧才是有效的,它被称之为当前栈帧,和这个栈帧相关联的方法称为当前方法。 执行引擎执行时的字节码指令都是针对当前栈帧进行操作的。下图,为栈帧的概念图。

下面我们重点来分享一下栈帧中的区域性变量表、 算子栈、 动态连线、 方法返回地址等各个部分的作用和资料结构。

区域性变量表区域性变量表是储存变数的内存空间,主要储存的是方法引数和方法内部定义的区域性变数。虚拟机器使用索引的方式访问区域性变量表中的变数,并且索引是从0开始的。在方法执行时,虚拟机器使用区域性变量表完成引数值到引数变数列表的传递过程。如果执行的是例项方法(非静态方法),那么区域性变量表中的第0个索引预设储存的是方法所属物件的例项,说白点也就是我们开发时所用的this关键字。

算子栈算子栈是一个后进先出的栈。算子栈可以储存任意的Java资料型别。当一个方法刚开始执行的时候,这个方法的算子栈是空的,在方法执行的过程中,会有各种字节码指令往算子栈中写入和提取内容,也就是出栈和入栈操作。 下面我们看一下如果在Java中执行两个int型别资料的相加,那么算子栈是怎么处理的。首先需要将两个int型别的资料执行入栈操作,并且保证,这两个int型别资料必须最接近栈顶。当执行这个相加指令时,会将这两个int型别资料进行出栈相加,然后将相加后的结果在执行入栈操作。算子栈中的资料型别必须与字节码指令匹配,就像上述说明中的相加操作,因为我们执行的是int型别的相加操作,所以在执行时,最接近栈顶的两个资料型别必须是int型别,不能出现一个long和一个float相加的情况。在编译器执行和类载入时,都会进行上述的校验操作。

在正常的情况下算子栈与算子栈都是互相独立的。但在虚拟机器优化时通常会做一些处理也就是两个算子栈会有重叠的部分,也就是方法呼叫时这一部分资料会被共享。目的是减少额外的引数传递和复制等操作。

动态连线每个栈帧都有一个指向执行时常量池该栈帧所属方法的引用,持有这个引用的目的是为了支援方法呼叫过程中的动态连线。 我们知道class档案的常量池中存有大量的符号引用,字节码中的方法呼叫就以常量池中指向方法的符号引用作为引数。 这些符号引用一部分会在类载入阶段或者第一次使用的时候就转化为直接引用,这种转化称为静态解析。 另外一部分将在每一次执行期间转化为直接引用,这部分称为动态连线。

方法返回地址当一个方法执行后,只有2种办法可以让虚拟机器退出这个方法。它们分别是:

执行引擎遇到任意一个方法返回的字节码指令,也就相当于return关键字。这种退出的方式叫做正常完成出口。另一种退出的方法是方法执行过程中遇到了异常。并且这个异常程式并没有处理,也就是在此方法的异常表中没有检索到匹配的异常处理器,就会导致方法退出。这种方式的退出叫做异常完成出口。方法退出的实际过程就是把当前栈帧出栈。方法退出所执行的具体逻辑是:恢复一个方法的区域性变量表和算子栈,把返回值(如果有的话)压入呼叫者栈帧的算子栈中,调整PC计数器的值以指向方法呼叫指令后面的一条指令等。

2019-09-08 13:56:00

相关文章