虚拟机字节码执行引擎(虚拟机是如何执行字节码指令的)

最近一直在学习《java虚拟机》这本书,根据自己的理解,进行如下总结,希望能和大家交流学习。
本节是对第八章8.4节的学习总结,关于:虚拟机字节码执行

基于栈的字节码解释执行引擎

一. java代码的执行

首先,我们要清楚,许多Java虚拟机的执行引擎在执行Java代码的时候,都有解释执行(通过解释器执行)和编译执行(通过即时编译器产生本地代码执行)两种选择, 本文首先探讨在解释执行时,虚拟机执行引擎是如何工作的.
虚拟机字节码执行引擎(虚拟机是如何执行字节码指令的)

二. 解释执行

大部分的程序代码(.java)到物理机的目标代码(机器码)或虚拟机能执行的指令集(字节码)之前,都需要经过下图中的各个步骤.图中下面那条分支,就是传统编译原理中程序代码到目标机器代码的生成过程,而中间的那条分支,就是解释执行的过程.

解释执行过程包含两步:编译+解释

虚拟机字节码执行引擎(虚拟机是如何执行字节码指令的)

编译 & 解释

在Java语言中, Javac编译器完成了:程序代码—词法分析—语法分析—抽象语法树—遍历语法树生成线性的字节码指令流(即.java文件—.class文件转换)的过程。这一部分动作是在Java虚拟机之外进行的, 而解释器在虚拟机的内部,所以Java程序的编译就是半独立的实现.如下图示意:

虚拟机字节码执行引擎(虚拟机是如何执行字节码指令的)

三,基于栈的指令集与基于寄存器的指令集

Java编译器经过编译(javac编译)后,输出的指令流(也可以理解为.class字节码文件)所属架构有两种,一是基于栈的指令集架构,指令流中的指令大部分都是零地址指令,它们依赖操作数栈进行工作. 另一套常用的指令集架构是基于寄存器的指令集,最典型的就是x86的二地址指令集。这些指令依赖寄存器进行工作. 两套指令集各有优势,并存发展。
虚拟机字节码执行引擎(虚拟机是如何执行字节码指令的)

基于栈的指令集与基于寄存器的指令集两者之间的区别

用书中的一个例子来说明两者之间的区别;我感觉简单易懂
虚拟机字节码执行引擎(虚拟机是如何执行字节码指令的)

基于栈的指令集的优点和缺点

优点:

可移植:寄存器由硬件直接提供,程序直接依赖这硬件寄存器则不可避免地要受到硬件的约束。使用栈架构的指令集, 程序不会直接使用这些寄存器,就可以由虚拟机实现来自行决定把一些访问最频繁的数据(程序计数器,栈顶缓存等) 放到寄存器中以获取尽量好的性能,这样实现起来也更加简单一些.
代码相对更加紧凑:字节码中每个字节就对应一条指令,而多地址指令集中还需要存放参数。
编译器实现更加简单 :不需要考虑空间分配的问题,所需空间都在栈 上操作。

缺点:

执行速度相对来说会稍慢:所有主流物理机的指令集都是寄存器架构也从侧面印证了这一点。完成相同功能所需的指令数量一般会比寄存器 架构多,因为出栈,入栈操作本身就产生了相当多的指令数量.更重要的是,栈实现在内存之中,频繁的栈访问也就意味着频繁的内存访问,相对于处理器来说,内存始终是执行速度 的瓶颈.尽管虚拟机可以采取栈顶缓存的手段,把最常用的操作映射到寄存器中避免直接内 存访问,但这也只能是优化措施而不是解决本质问题的方法.由于指令数量和内存访问的原 因,所以导致了栈架构指令集的执行速度会相对较慢.

基于寄存器的指令集的优点和缺点

优点:

执行速度快,性能高

缺点:

寄存器由硬件直接提供,程序直接依赖这硬件寄存器则不可避免地要受到硬件的约束.

四. 基于栈的解释器执行过程

接下来,列举书中的一个例子,说明java代码在虚拟机中是如何执行的。
虚拟机字节码执行引擎(虚拟机是如何执行字节码指令的)
虚拟机字节码执行引擎(虚拟机是如何执行字节码指令的)
javap提示这段代码需要深度为2的操作数栈和4个Slot的局部变量空间,清单8-17执行过程 ,操作数栈和 局部变量表的变化情况如下图所示:
虚拟机字节码执行引擎(虚拟机是如何执行字节码指令的)
虚拟机字节码执行引擎(虚拟机是如何执行字节码指令的)
虚拟机字节码执行引擎(虚拟机是如何执行字节码指令的)
虚拟机字节码执行引擎(虚拟机是如何执行字节码指令的)
虚拟机字节码执行引擎(虚拟机是如何执行字节码指令的)
虚拟机字节码执行引擎(虚拟机是如何执行字节码指令的)
虚拟机字节码执行引擎(虚拟机是如何执行字节码指令的)
上面的执行过程仅仅是一种概念模型,虚拟机最终会对执行过程做一些优化来提高性能,实际的运作过程不一定完全符合概念模型的描述。更准确地说,实际情况会和上面描述的概念模型差距非常大,这种差距产生的原因是虚拟机中解析器和即时编译器都会对输入的字节码进行优化,例如,在HotSpot虚拟机中,有很多以“fast_”开头的非标准字节码指令用 于合并,替换输入的字节码以提升解释执行性能,而即时编译器的优化手段更加花样繁多。不过,我们从这段程序的执行中也可以看出栈结构指令集的一般运行过程,整个运算过 程的中间变量都以操作数栈的出栈,入栈为信息交换途径,符合我们在前面分析的特点。