什么是JIT编译器?
Posted 流楚丶格念
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了什么是JIT编译器?相关的知识,希望对你有一定的参考价值。
文章目录
什么是JIT编译器?
这篇还是以问问题形式:
什么是解释器?什么是编译器?
目前主流的商用Java虚拟机,比如HotSpot、OpenJ9等,内部都同时包含解释器与编译器。
解释器(Interpreter):
在计算机科学中,解释器是一种计算机程序,它直接执行由编程语言或脚本语言编写的代码,并不会把源代码预编译成机器码,简单点:解释器会直接一行一行的读取源代码,解释,然后立即执行。
java虚拟机(jvm)启动时,会根据预定义的规范对字节码采用逐行解释的方式执行,也就是将字节码文件中的每条内容都翻译成系统能识别的指令并执行(这里就不看中间的过程)。
注意:这里是直接执行,并没有编译出什么文件(就算有也是部分临时的),相当于实时翻译并执行。
编译器(Compiler):
编译器负责把一种编程语言(通常为高级语言)“翻译”成另外一种语言(通常为低级语言),后者往往是二进制的形式的机器语言,被称为目标代码(object code),这个转换的过程通常的目的是生成可执行的程序。
在java中,将.java编译为.class文件就是编译器的一种操作。之后运行时又将.class编译成计算机CPU可以直接执行的机器语言,这也是编译操作。
注意:这里并没有直接执行,只负责完整、彻底的翻译,然后生成翻译后的文件,并没有任何执行的操作。
为什么Java是半编译半解释语言
关于这个,有两种说法,都挺有道理的,咱也不知道哪个对,哎,十年后我再来改!!!!!!
但是我们没必要争论这个其实,因为Java是半编译半解释语言这已经是事实了!
说法1:先编译后解释
编译型语言是将源码编译成机器指令的文件,直接就可以执行,C/C++就是这种。而java也是通过编译将源码java文件编译成字节码文件(.class),所以它显然具有编译的特点。
解释型语言是在运行时一句一句的读取源码,一边翻译成机器指令一边执行。而java在运行时也是通过jvm读取字节码文件,一边翻译一边解释成机器指令并执行,所以它显然也具有解释的特点。
所以java是半编译半解释型语言。
说法2:一边解释一边编译
jvm支持一种叫即时编译的技术,它被称之为:JIT(Just in time compiler)编译器。也就是jvm不仅仅有解释器的作用,它其实还有编译器的作用。
jvm在执行java程序时,通常会将解释执行和编译执行二者结合起来进行,也就是一边解释一边编译。
所以java是半编译半解释型语言。
什么是JIT编译器(Just in time compiler),它的作用是?
众所周知,解释器的设计和实现上比较简单,执行程序的效率又比编译器编译出来的程序慢。java一开始也是如此,但是它并没有不思进取,为了解决这个问题,后面JVM就开始使用HotSpot VM这个java虚拟机了。
没错,JVM并不具体指代一种虚拟机,甚至当初有很多种JVM相互竞争,百家争鸣,当然随着时间的推移,逐渐统一了。
而HotSpot VM的一大功能就是JIT(Just in time compiler:即时编译器)。
JIT也是一种编译器,可以将读取到的字节码文件编译成本地机器可以直接执行的机器语言。
但是它并不是完全将所有文件都编译后才执行的,如果是这样,那java就可以完全叫编译型语言了。JIT只会编译所谓的热点代码(也有叫热点方法、热点函数的)
扩展:热点代码
JVM进行一段代码是不是热点代码,是不是需要触发即时编译,这样的行为称为热点探测,其实进行热点探测并不一定要知道方法被调用了多少次。
主要的探测方法:
- 基于采样的热点探测:主要是虚拟机会周期性的检查各个线程的栈顶,若某个或某些方法经常出现在栈顶,那这个方法就是“热点方法”。优点是实现简单;缺点是很难精确一个方法的热度,容易受到线程阻塞或外界因素的影响。
- 基于计数器的热点探测:主要就是虚拟机给每一个方法甚至代码块建立了一个计数器,统计方法的执行次数,超过一定的阀值则标记为此方法为热点方法。
Hotspot使用的基于计数器的热点探测方法。然后使用了两类计数器:方法调用计数器和回边计数器。当到达一定的阀值是就会触发JIT编译。
- 方法调用计数器 在JVM client模式下的阀值是1500次,Server是10 000次。可以通过虚拟机参数: -XX:CompileThreshold设置。但是JVM还存在热度衰减,时间段内调用方法的次数较少,计数器就减小。
- 回边计数器:主要统计的是方法中循环体代码执行的次数。
总之最重要的是,它是在JVM启动后进行编译的,也就是解释器一边在启动运行程序,JIT一边默默的将热点代码编译为机器语言的指令,这种编译方式也被称为动态编译。
在程序初启动时,完全依靠解释器运行,编译器就像个拖油瓶,在那慢吞吞的准备。但是通过时间的推移,编译器的作用开始发挥了,越来越多的代码被编译成机器指令,这些复杂的代码不再需要通过解释器一行一行解释执行了,而是直接就可以通过编译出的机器码运行了,所以程序会越运行越快。
扩展:静态编译和动态编译:
静态编译就是在程序执行前的编译,它并不启动任何程序,只是相当于将整篇文章(源码)翻译了一遍。在Java中,将.java文件编译为.class文件就是静态编译,又名前端编译。
动态编译则是在程序运行时进行的编译,它在程序启动后才开始进行编译工作,在JVM中,JIT编译就是动态编译,它将字节码文件编译为本地的机器码,并进行优化,这又名后端编译。
说到这肯定又蒙了什么是HotSpot VM?
什么是HotSpot VM?它和JIT的关系是?
HotSpot VM是一个由C++编写的Java虚拟机,也是目前范围最广的Java虚拟机,但它其实一开始并非Sun公司开发的,而是一个小公司设计的,只是后面被Sun发现并收购了而已。可能到这里我们才意识到,java虚拟机并不只有一家,另一个有名的是JRockit VM虚拟机。不过我们也无需担心,因为它也早在08年左右被Oracle一起收购了,我们现在只需要知道HotSpot VM就可以了。
HotSpot VM可以视为JVM的实现,它主要功能包括一个解释器和两个编译器,这两个编译器就可以合称为JIT编译器了。没错,JIT编译器并不是一个编译器,它是分为了两种模式的编译器:client模式和server模式。
client模式是一种轻量级编译器,也叫C1编译器,占用内存小,启动快,耗时短,它会进行简单并可靠的优化,更注重效率。
server模式是一种重量级编译器,也叫C2编译器,启动慢,占用内存大,耗时长,但编译的代码执行效率更高,甚至会根据性能监控信息进行一些不可靠的激进优化,更注重质量。
为啥注重质量却反而不可靠了呢?或许是因为对完美的追求太高了,进行了一些钻了牛角尖的优化吧。但是不用担心,一般在方法优化失败时,程序会撤销C2编译的这部分代码,重新用解释器进行解释执行。
解释器与编译器怎么交互的?
当程序需要迅速启动和执行时,解释器可以首先发挥作用,省去编译的时间,立即执行。在程序运行后,随着时间的推移,编译器把越来越多的代码编译成本地代码后,可以获取更高的执行效率。
当程序运行环境中内存资源限制较大(如部分嵌入式系统),可以使用解释执行节约内存,反之可以使用编译执行提升效率。
解释器可以作为编译器激进优化时的一个“逃生门”,让编译器根据概率选择一些大多数时候都能提升运行速度的激进优化手段,当激进优化不成立时,可以通过逆优化退回到解释状态继续执行。
以上是关于什么是JIT编译器?的主要内容,如果未能解决你的问题,请参考以下文章