【JVM】整体结构(三):执行引擎

在前面两篇文章,我们介绍了类加载子系统和运行时数据区

本篇我们就来看看 JVM 的最后一个部分,执行引擎。

JVM 的主要任务是负责装载字节码到其内部,但字节码并不能够直接运行在操作系统之上,因为字节码指令并非等价于本地机器指令,它内部包含的仅仅只是一些能够被JVM锁识别的字节码指令、符号表和其他辅助信息。

那么,如果想让一个Java程序运行起来,这就涉及到了JVM的字节码执行引擎。执行引擎其实就是个运算器,能识别输入的指令,并根据输入指令执行一套特定的逻辑,最终输出特定的结构(对应平台上的本地机器指令)。

相比于JVM,物理机的执行引擎是由硬件实现的(CPU),而虚拟机的执行引擎由于自己实现的,但它们的处理流程是相似的:

  1. 取值:JVM 内部定义了两百多个字节码指令,不同字节码指令的实现机制都是不同的
  2. 译码:JVM 取出字节码指令后,需要将其翻译为不同的逻辑,然后才能执行(译码的作用)
  3. 执行:分为两个阶段,取操作数与进行运算
  4. 不断重复上面过程,最终输出输出对应平台上的本地机器指令

注意:在 jdk 1.0时代,Java虚拟机完全是解释执行的,随着技术的发展,现在主流的虚拟机中大都包含了即时编译器(JIT),所以,当前Java字节码的执行有两种方式:

  1. 即时编译方式(执行快):解释器先将字节码编译成机器码,然后再执行该机器码。
  2. 解释执行方式(启动快):解释器通过每次解释并执行一小段代码来完成Java字节码程序的所有操作。

通常采用的是第二种方法。由于JVM规格描述具有足够的灵活性,这使得将字节码翻译为机器代码的工作具有较高的效率。对于那些对运行速度要求较高的应用程序,解释器可将Java字节码即时编译为机器码,从而很好地保证了Java代码的可移植性和高性能。但在虚拟机在真正执行代码过程中,到底是解释执行还是编译执行,只有它自己才能准确判断了。

基于栈的代码执行示例

在上一篇文章中,我们介绍了每个虚拟机栈都是由一个或多个方法的栈帧构成,而每个栈帧又是由局部变量表、操作数栈、动态链接、方法出口。现在我们通过一个例子,来看看执行引擎到底是怎样译码并执行的。

1)示例代码

public class Demo {

    public int math() {
        int a = 1;
        int b = 2;
        int c = (a + b) * 10;
        return c;
    }
	
	// 入口
    public static void main(String[] args) {
        Demo demo = new Demo();
        int math = demo.math();
    }
}

2)编译并且class文件,然后将其反编译成我们能看懂的文件。

这里再额外提一句,编译过程:Demo.java -> 词法分析器 -> tokens流 -> 语法分析器 -> 语法树/抽象语法树 -> 语义分析器 -> 注解抽象语法树 -> 字节码生成器 -> Demo.class文件

javac Demo.java // person.class都是不可读的字节码文件(注:若不可读则用sublime打开)
javap -c -l Demo > Demo.txt // 反编译当前class文件,生成汇编代码,并重定向到Person.txt

得到的汇编代码如下图所示,这里只对math方法的指令进行了注释,更多JVM指令可以查阅 指令助记符总结及基本指令大全

在这里插入图片描述

3)我画了个每条指令执行的流程图,math 函数的执行其实就是靠操作数栈和局部变量表的协作完成。

在这里插入图片描述

最后再说一句,若栈调用过深,那么可能会抛出异常 StackOverFlowError(栈溢出)。

JVM整体结构图

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

A minor

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值