天天看点

JVM - 执行引擎

1. 概述

虚拟机是一个相对物理机的概念,这两种机器都有代码执行能力,其区别是物理机的执行引擎是建立在处理器,缓存,指令集和操作系统层面上的,而虚拟机执行引擎则是由软件自行实现的,因此可以不受物理条件制约地定制指令集和执行引擎的结构体系,能够执行那些不被硬件直接支持的指令集格式

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

为了让一个Java程序跑起来,执行引擎的任务就是将字节码指令解释/编译为对应平台上的本地机器指令才可以,简单来说,JVM中的执行引擎充当了将高级语言翻译为机器语言的译者

JVM - 执行引擎

注意这里需要区分一下:

Java的编译期其实是一段不确定的操作过程,一共有三种

  • 前端编译器(叫编译器的前端更准确)把

    *.java

    文件转换为

    *.class

    文件的过程,前端编译器有

    Sun

    Javac

    Eclipse JDT

    中的增量式编译器等
  • 后端运行期编译器(JIT编译器,

    Just In Time Compiler

    )把字节码转换为机械码的过程,主要有

    HotSpot VM

    C1

    C2

    编译器
  • 静态提前编译器(AOT编译器,Ahead Of Time Compiler)直接把

    *.java

    文件编译成本地机械码的过程,有

    GCN Compiler for the java

这里说的执行引擎是在说后两种

执行引擎在执行的过程中需要执行什么样的字节码指令依赖于程序计数器

2.

Java

代码编译和执行过程

Java代码编译是由Java源码编译器(Java前端编译器)来完成(与JVM无关)

JVM - 执行引擎

对于前端编译器生成的线性的字节码指令流,有两种选择,这两种不同的选择也解释了什么叫半解释半编译语言(指的是既可以解释执行,也可以编译执行)

  • 解释执行:也就是说可以通过解释器逐行解释执行,也就是将每条字节码文件中的内容逐一翻译为对应平台的本地机器指令并执行
  • 编译执行:先通过编译器全部编译成对应的机器语言,但是这个时候还不执行,等全部翻译完可以对指令做一个缓存,对指令进行优化,之后再执行
    JVM - 执行引擎

2.1 解释器(解释执行)

  • 解释器真正意义上所承担的角色就是一个运行时“翻译者”,将字节码文件中的内容“翻译”为对应平台的本地机器指令执行。
  • 当一条字节码指令被解释执行完成后,接着再根据PC寄存器中记录的下一条需要被执行的字节码指令执行解释操作。

这里关于Java语言跨平台的特性有一个问题:

Java语言之所以能够跨平台是因为Java的源程序被编译生成字节码文件,字节码文件又被不同平台的JVM解释成对应平台的机器指令,从而实现了跨平台的特性;但是,中间为什么需要一步源程序到字节码文件的转换呢?为什么不直接将Java程序交给不同平台的JVM解释成对应平台的机器指令?

  • 网上说是这样降低了JVM的压力,把解释分为了前端解释器生成字节码文件,再让JVM只根据字节码生成机器指令,更快
  • 同时语法是会变的,而源代码中没有版本信息,而字节码中不但有版本信息,还可以经由编译过程抹平一些语言层面的变化(即语言语法虽然有变化,但字节码依然遵照原来的规则即可)
  • 字节码也可以由其他语言生成,如Groovy,Clojure,Scala。需要注意的事,既然这些语言可以编译成字节码,也就可以被Java或其他JVM语言调用

当Java虚拟机启动时会根据预定义的规范对字节码采用逐行解释的方式执行,将每条字节码文件中的内容翻译为对应平台的本地机器指令直接执行

现在这种解释器执行的方式被视为低效的代名词,为了解决这个问题,JVM平台支持了即时编译的功能;

即时编译的目的是避免函数被解释执行,而是将整个函数编译成为机器码,每次函数执行时,只执行编译后的机器码即可,也就是说,有一定的缓存作用

2.2

JIT

编译器(编译执行)

JVM平台支持一种叫作即时编译的技术。即时编译的目的是避免函数被解释执行,而是将整个函数体编译成为机器码,每次函数执行时,只执行编译后的机器码即可,这种方式可以使执行效率大幅度提升

虚拟机将方法编译成机器码,缓存起来,之后再要执行这个方法就直接去找缓存起来的机器码,更为高效,在编译的过程也可以进行优化

2.3 解释器和编译器共存

HotSpot VM是采用解释器与即时编译器并存的架构,他们各自的取长补短,在程序刚启动的时候,解释器马上可以发挥作用,省去编译的时间,响应的速度快;随着程序运行时间的推移,即时编译器逐渐发挥作用,根据热点探测功能,将有价值的字节码编译成本地机器码,以换取更改的程序执行效率

也就是说在此模式下,当Java虚拟器启动时,解释器可以首先发挥作用,而不必等待即时编译器全部编译完成后再执行,这样可以省去许多不必要的编译时间。随着时间的推移,编译器发挥作用,把越来越多的代码编译成本地代码,获得更高的执行效率

2.4

AOT

编译器

比起

JIT

AOT

是在程序运行之前,将字节码转换为机器码

继续阅读