JAVA是解释执行语言,还是编译执行语言?
在最早的时候(JIT诞生前),如果问一个JAVA开发者,JAVA是解释执行的语言还是编译执行的语言,相信100%的人都会回答“解释执行”。
但是到了今天,再说JAVA是解释执行的就不正确了
为什么呢?跟JIT有关
什么是JIT(Just In Time)
通常情况下,JVM会加载.class文件,并在程序执行时,逐行读取、解释、执行
JIT是JVM的即时编译器,能够让JVM把代码编译成机器码,这样在执行这一段代码时,可以直接执行机器码,相对于解释一行执行一行的“解释执行”而言,效率大幅度提高。在执行这一段代码的时候,JAVA就是“编译执行”的模式
目前主流的HotSpot虚拟机默认是解释执行+编译执行共存的模式。JVM会自动将频繁执行的代码片段编译成机器码,这样就避免了频繁解释相同的代码带来的性能浪费
到这里问题就来了,既然编译执行速度比解释执行快很多,为什么不干脆把所有字节码都编译成机器码呢?接下来我们就来探讨这个问题
为什么不全部代码都编译成机器码?
如果我们要把java代码编译成机器码,可以在两个阶段进行,分别是 源码编译时和JVM加载.class文件字节码时,但是他们都各自有不同的问题
编译源码时,直接编码成机器码
首先,技术上是完全可行的
但是,JAVA很重要的一项特性,就是跨平台,号称“一次书写,随处运行”。如果编译源码时直接编译成机器码,那么就失去了跨平台的特性了,因为不同CPU、不同系统内核可执行的机器码是不一样的。所以这个方案行不通
JVM加载CLASS文件时,直接用JIT技术全部编译成机器码
技术上依然是可行的
但是将代码编译成机器码是有代价的,那就是
编译耗时将会导致JAVA程序启动时间大幅度延长
以及
编译后的机器码需要占用大量内存
对于启动时间延长的问题,我们可能会说,在服务器上,启动时间变长并非完全不能接受,毕竟谁的服务会经常重启呢
没错,但是这不足以让JVM的开发者们完全把代码都编译成机器码。但是,HotSpot JVM在server模式运行的时,会更容易倾向于把代码编译成机器码,表现在对“热点代码”的判断严格程度比client模式要宽松,但是依然没有将全部代码都编译成机器码
第二点,对于内存资源的占用就比较难办了,近些年来,内存资源变得不再像以前一样昂贵和紧缺,但是在过去很长一段时间里,内存都不是我们可以随意挥霍的资源。结合成本和收益来考量,主流的JVM还是没有把全部代码都编译成机器码
但是oracle JDK9 提供了实验性质的AOT((Ahead-of-Time Compilation)功能,支持把class文件直接编译成机器码文件,这样就省去了JIT的工作,启动时,直接使用编译后的文件启动即可