深入理解Java虚拟机之(三):JVM中即时编译器JIT与解释器

.(一):解释器模式与编译器模式以及混合模式
    其实jvm(HotSpot为例)翻译字节码文件分为两种方式,一种是解释执行,另一种是即时编译。所谓解释执行就是边翻译为机器码边执行,而即时编译就是先将一个方法中的所有字节码全部编译成机器码之后再执行。前者不需要等待编译,翻译一部分就可以执行一部分,而后者在编译完成后,实际的运行速度更快,在HotSpot中默认采用混合模式,其先解释执行字节码,然后将其中的热点代码(多次执行,循环等)直接编译成机器码,下次就不用再编译了,让其更快速地运行。
    但是在生产环境中,为何不都采用即时编译的模式呢?如果服务端的代码改动的频率不高,花点时间去编译,且不是在运行时能够获得更高的效率?
    即时编译运行速度确实快,但是全部采用即时编译的话,jvm无法获得程序的运行时信息,这就使得jvm无法对代码进行很好的优化,而如果先执行进行解释执行的话,是真真实实把整个代码都跑了一遍,jvm知道哪里有坑,哪里需要重点关注,jvm会根据代码的执行情况进行更多的优化,而不仅仅是编译为机器码;再者我们的代码其实也符合二八定律,即80%的代码都不用占用虚拟机很多的计算资源,大约为20%,而对于20%的热点代码需要消耗虚拟机80%的计算资源。编译完的机器码需存储到磁盘上,这也需要占用比较大的存储空间,想想,我们这里很大一部分代码根本就不需要消耗我很多的计算成本的,而需要占用大量的磁盘空间,这样看也是划不来的~

1.解释器模式
  一条一条地读取,解释并且执行字节码指令。因为它一条一条地解释和执行指令,所以它可以很快地解释字节码,但是执行起来会比较慢,没有JIT的配合下效率不高。

2.JIT编译器模式
  即时编译器把整段字节码不加筛选的编译成机器码不论其执行频率是否有编译价值,在程序响应时间的限制下,没有达到最大的优化。

3.混合模式
  在解释执行的模式下引入编译执行,刚好可以弥补相互的缺点,达到更优的效果。

        程序刚开始启动的时候,因为解释器可以很快的解释字节码,所以首先发挥作用,解释执行Class字节码,在合适的时候,即时编译器把整段字节码编译成本地代码,然后,执行引擎就没有必要再去解释执行方法了,它可以直接通过本地代码去执行它。执行本地代码比一条一条进行解释执行的速度快很多,主要原因是本地代码是保存在缓存里的。

混合模式下其各自的特点主要如下:

解释器:
    程序启动时首先发挥作用,解释执行Class字节码;
    省去编译时间,加快启动速度;
    但执行效率较低;

JIT编译器:
    程序解释运行后,JIT编译器逐渐发挥作用;
    编译成本地代码,提高执行效率;
    但占用程序运行时间、内存等资源;

(三):热点代码

    在刚开始的时候,jvm不知道这段代码,是否会频繁的调用方法,或是一个循环,也就是这段代码被多次执行,因此刚开始的时候并不会编译代码,将代码翻译成 java 字节码相对于编译这段代码并执行代码来说,要快很多。编译器回去衡量哪些方法会被频繁调用,如果一个方法的执行频率超过一个特定的值的话,那么这个方法就会被JIT编译成本地代码。而这个方法或代码块因其运行特别频繁,就会认为这是“热点代码”(Hot Spot Code)。当 JVM 执行某一方法或遍历循环的次数越多,就会更加了解代码结构,那么 JVM 在编译代码的时候就做出相应的优化。

热点代码分为二类:
    多次被调用的方法
    多次被执行的循环体
    检测热点代码:

方法计数器:
    记录方法调用的次数

回边计数器:
    记录代码块循环次数

    当计数器数值大于默认阈值或指定阈值时,方法或代码块会被编译成本地代码。

(四):总结

整个java应用程序的执行过程如下:

1、源代码经javac编译成字节码,class文件

2、程序字节码经过JIT环境变量进行判断,是否属于“热点代码”(多次调用的方法,或循环等)

3、如是,走JIT编译为具体硬件处理器(如sparc、intel)机器码

4、如否,则直接由解释器解释执行

你可能感兴趣的:(java,深入理解Java虚拟机)