1、编译分类
1.1、前端编译
把Java源文件编译为Class文件的过程。常见的前端编译器:
- Oracle Javac
- Eclipse JDT中的增量式编译器(ECJ)
1.1.1、优点
- 辅助实现了Java新语法:泛型、内部类等;
- 编译成Class文件直接给JVM解释器执行,省去编译时间,加快启动速度。
1.1.2、缺点
- 几乎没有做任何措施优化代码的运行效率;
- 解释器执行效率低。
1.2、后端编译
在JVM运行时,通过内置的即时编译器(Just In Time Compiler-JIT),把Class文件字节码编译为本地机器码。
常见的后端编译器:
- HotSpot虚拟机的C1、C2编译器。
1.2.1、优点
- 运行时收集监控信息,把热点代码编译为本地机器码,并进行各种优化,例如:
- 运行数据分析,把堆栈操作转换为寄存器操作;
- 消除子表达式等
- 大大提升了执行效率。
当使用JIT编译器是,与解释执行相比,本地机器码很容易由硬件执行,将大大提高执行速度。
1.2.2、缺点
- 收集监控信息影响程序运行;
- 编译过程占用时间,使得启动速度变慢等;
- 编译过程占用内存;
- 使用较少的diam的程序无法从即时编译中收益。
1.3、静态提前编译
Ahead Of Time AOT编译
在运行期直接把Jaa源文件编译为本地机器码。
1.3.1、优点
- 编译不占用运行时间,加快启动速度;
- 编译本地机器码直接保存到磁盘,不占用内存。
1.3.2、缺点
- Java语言动态性带来了额外复杂度,影响静态编译代码的质量;
- 此方式一般不如JIT编译的质量。
2、三种执行模式
JVM中有三种执行模式:解释执行、混合模式和编译执行,默认情况下处于混合模式。
如果想看虚拟机的执行模式,可以执行以下命令:
1 | java -version |
2.1、解释执行模式
该模式下表示全部代码均是解释执行,不做任何JIT编译,如果要开启这种模式,请使用-Xint
参数:
1 | java -Xint -version |
这种模式会降低运行速度,通常低10倍或者更多。
2.2、编译执行模式
该模式下不管是否热点代码,对所有的函数,都进行编译执行,如果要开启这种模式,请使用-Xcomp
参数:
1 | java -Xcomp -version |
JVM在第一次使用时就会把所有的字节码编译为本地代码,从而优化执行速度,绕开缓慢的解释器。但是这种模式没有让JVM启用JIT编译器的全部功能。
2.3、混合模式
JVM默认的执行模式,部分函数会解释执行,部分会编译执行。如果函数调用频率高,被反复使用,就会认为是热点代码,该函数就会被编译执行。