问题描述
HotSpot是较新的Java虚拟机技术,用来代替JIT技术,那么HotSpot和JIT是共存的吗?题主可能对“HotSpot”和“JIT”的所指还感到模糊。
“HotSpot”这个具体的拼写方式通常指的是一个JVM实现的名字——HotSpot VM。这个JVM最初由Longview/Animorphic实现,随着公司被Sun/JavaSoft收购而成为Sun的JVM,并于JDK 1.3.0开始成为Sun的Java SE的主要JVM。在Sun被Oracle收购后,现在HotSpot VM是Oracle的Java SE的主要JVM。
然后,“hot spot”这个拼写方式则通常指比较宽泛的“热点”概念。在执行引擎的上下文中,“热点”指的是执行频率高的代码。至于“执行频率高的代码”是以什么为单元,是“方法/函数”级别还是“某条执行路径(trace)”级别,都可以;这是实现者可以选择的点。
HotSpot VM得名于它得混合模式执行引擎:这个执行引擎包括解释器和自适应编译器(adaptive compiler)。
默认配置下,一开始所有Java方法都由解释器执行。解释器记录着每个方法得调用次数和循环次数,并以这两个数值为指标去判断一个方法的“热度”。显然,HotSpot VM是以“方法”为单位来寻找热点代码。
等到一个方法足够“热”的时候,HotSpot VM就会启动对该方法的编译。这种在所有执行过的代码里只寻找一部分来编译的做法,就叫做自适应编译(adaptive compilation)。
为了实现自适应编译,执行引擎通常需要有多层:至少要有一层能够处理初始阶段的执行,然后再让自适应编译处理其中部分代码。
JIT编译,全称 just-in-time compilation,按照其原始的、严格的定义,是每当一部分代码准备要第一次执行的时候,将这部分代码编译,然后跳进编译好的代码里执行。这样,所有执行过的代码都必然会被编译过。早期的JIT编译系统对同一个块代码只会编译一次。
JIT编译的单元也可以选择是方法/函数级别,或者别的,例如trace。
严格说JIT编译与自适应编译相比:
* 前者的编译时机比后者早:第一次执行之前 vs 已经被执行过若干次
* 前者编译的代码比后者多:所有执行过的代码 vs 一部分代码
JIT编译与自适应编译都属于“动态编译”(dynamic compilation),或者叫“运行时编译”的范畴。特点是在程序运行的时候进行编译,而不是在程序开始运行之前就完成了编译;后者也叫做“静态编译”(static compilation)或者AOT编译(ahead-of-time compilation)。
现在“JIT编译”这个名词已经被泛化为等价于“动态编译”,所以包含了严格的JIT编译和自适应编译。
就这个角度说,HotSpot VM仍然在使用“JIT编译”;里面的Client Compiler(C1)和Server Compiler(C2)也常被称为“JIT编译器“。要注意,这样的说法已经不是指严格意义上的“JIT”了。
=========================================================
然而事情还可以更加复杂。换一个JVM实现,来看看JRockit VM。这个JVM使用纯编译的执行引擎,没有解释器。但它有多层编译:第一次执行某个方法之前会用非常低的优化级别去JIT编译,然后等到某个方法足够热之后再用较高的优化级别重新编译它。
这种系统既是严格意义上的JIT编译(第一次执行某个方法前编译它),又是自适应编译(找出热点再进行编译)。
加入Crankshaft编译架构之后的V8 JavaScript引擎也是如此:有两层编译,第一次是严格的JIT编译而第二层是自适应编译。
所以说JIT编译与自适应编译可以共存。只不过HotSpot VM因为有解释器来承担第一层执行的任务,所以不使用JIT编译而已。