文章目录
1.概述
jvm将java字节码文件转换为与当前平台相关的二进制机器码的过程,是由jvm中的执行引擎来处理,与javac将java文件转化为.class文件的前端编译不同,javac并不处于jvm体系,且执行引擎是java虚拟机核心组成部分之一,它的任务是将字节码指令解释/编译
为对应平台上的机器指令
在执行引擎工作过程中,它需要执行的字节码指令是依赖于pc寄存器的,这一过程可以去看
Java虚拟机-pc寄存器执行过程理解
2.解释器和编译器概述
字节码文件被加载到内存中后就等待被执行了,执行这些代码需要依靠执行引擎,在目前主流的比如HotSpot,OpenJ9虚拟机中,执行引擎中有解释器(Interpreter)
和即时编译器(Just In Time,JIT)
两种方式来将字节码文件转化为机器码指令,解释器会对字节码采用逐行解释方式执行,将字节码文件中的内容转化为对应平台的机器码,而编译器是直接将用的比较多的代码编译成本地代码,生成缓存(cached
)放在方法区
中,这样可以减少解释器的中间消耗,获得更高的执行效率
3.java是半编译半解释型语言
java在JDK1.0
时代,程序都是通过解释器
来执行的,所以java在最初的时候运行速度是不如C/C++
的,后来虚拟机发展了即时编译器
可以直接生成本地缓存,java程序的执行效率得到大大提升,现在的jvm在执行java代码的时候既可以通过解释器执行,也可以通过即时编译器执行,,但大多数情况下将两者结合使用,所以将Java称为半编译半解释型语言
3.1关于java跨平台性的补充
java的跨平台性主要指的时class文件的跨平台,java文件和C/C++不同,可以做到一处编译,到处运行主要得益于jvm,作为虚拟机,比如CentOs
,我们可以只用下载一个镜像系统就可以使用一个截然不同的操作系统,不受制于硬件的约束,jvm也是如此,只需要与之对应平台的操作系统就可以执行class文件,而class文件是一种中间状态的二进制文件,需要转义后才能称为机器码,类似C++的源文件,经编译为汇编后在转为机器码
4.HotSpot中的解释器和JIT编译器
java一共有两种解释器:古老的字节码解释器和现在普遍使用的模板解释器,字节码解释器逐行执行字节码,效率非常低下,模板解释器顾名思义,套模板,和我们写作文时套用模板一样,可以提高解释器的性能,虽然性能有所提高,但效率仍然比不C/C++,运用解释器执行的还有Python,Ruby等高级语言,为了解决这个问题,JVM平台支持了一种即时编译的技术,将越来越多的代码编译成本地代码缓存,避免被解释执行,下一次用的时候就可以直接执行编译好的机器码,效率很高
那么既然编译器效率如此高,为什么HotSpot仍然要使用解释器和即时编译器并存的架构?
JRockit
虚拟机就没有解释器,目前已经不再发展了,我们需要知道,这两种架构各有优缺点
- 在程序启动时,解释器可以立马发挥作用,省去编译时间,立即执行,而编译器要先把代码编译为本地代码,要一定的时间,但编译完成后效率很高
HotSpot虚拟机的方案时:当程序需要迅速启动并执行时,解释器首先发挥作用,一旦程序启动,随着时间推移,编译器发挥作用,减少解释器的中间损耗,获得更高的执行效率,并且解释器可以充当编译器在激进优化不成功的时候的逃生门
5.判断是否使用JIT编译器
前面我们说过编译器的优点,那么什么情况下使用编译器呢?当虚拟机发现某个方法或代码块用的特别频繁,就会把这些代码认定为热点代码,为了优化热点代码的执行效率,就可以使用编译器,这里的热点代码主要有两类:
- 被多次调用的方法
- 被多次执行的循环体
热点代码经过JIT编译器编译为本地机器指令的编译方式被称为栈上替换(OSR,On Stack Replacement)编译
,一个方法或循环体究竟需要被调用几次,执行多少次循环才能被当作热点代码? 目前HotSpot虚拟机采用的热点探测技术是基于计数器的热点探测
5.1方法调用计数器
这个计数器就是用于统计方法被调用的次数,它的阈值在Client
模式下是1500次,在Server
模式下是10000次,我们常用的JDK都是Server模式,
当一个方法被调用时,回先检查该方法是否存在被JIT编译过的版本,如果存在就会使用编译后的本地代码来执行,如果不存在则将此方法的阈值加1,然后判断是否达到阈值,如果达到,则会提交一个该方法的代码编译请求,具体过程如下:
5.2热度衰减
在这种情况下,如果不做任何处理,那么每一个方法的调用都会使得其阈值不断增加,最终被编译,JVM采用的是一段时间内方法被调用的次数,当超过一定时间限度,如果这个方法的调用次数未达到阈值,次数则会减少一半,这个过程被称为热度衰减
,这段时间被称为半衰周期
,我们可以通过设置参数来调整绊摔周期:-XX:CounterHalfLifeTime设置,单位是S,
-XX:-UseCounterDeacy来关闭热度衰减
5.3设置程序执行方式
- -Xint:完全采用解释器模式
- -Xcomp:完全采用编译器模式,如果编译出现问题,解释器会介入
- -Xmixed:采用解释器+编译器混合模式
6.JIT编译器分类
HotSpot虚拟机不光有两种架构的执行引擎,对JIT编译器又内嵌了两种编译器分别为Client Compiler
和Server Compiler
,简称为C1和C2编译器,可通过如下命令选择具体哪一种编译器
- -client:运行在client模式下,使用c1编译器,c1编译器会对字节码文件进行简单和可靠的优化,耗时短,达到更快的编译速度
- -server:运行在server模式下,使用c2编译器,c2进行耗时较长的优化,以及激进优化,但代码执行效率更高
说明:当JDK是64位版本,默认是server模式,C2编译器启动时长比C1编译器慢,但系统稳定后,C2编译器执行速度远高于C1编译器