我知道 Microsoft .NET 使用 CLR 作为 JIT 编译器,而 Java 则使用 Hotspot。它们之间有什么区别呢?
我知道 Microsoft .NET 使用 CLR 作为 JIT 编译器,而 Java 则使用 Hotspot。它们之间有什么区别呢?
它们是非常不同的东西。正如人们指出的那样,CLR在执行MSIL代码之前编译成机器码。这使得除了典型的死代码消除和内联私有优化外,它还可以利用目标机器的特定CPU架构(尽管我不确定它是否这样做)。这也会为每个类带来一些负面影响(尽管编译器相当快速,许多平台库只是Win32 API的薄层包装)。
HotSpot VM采取了不同的方法。它认为大部分代码很少被执行,因此不值得花费时间进行编译。所有字节码都以解释模式开始。VM在调用点保留统计信息,并尝试识别被调用超过预定义次数的方法。然后,它仅使用快速JIT编译器(C1)编译这些方法,并在运行时交换方法(这就是HS的独特之处)。在C1编译的方法被调用多次后,同一方法会用缓慢但复杂的编译器进行编译,并再次交换代码。
由于HotSpot可以在方法运行时交换方法,所以VM编译器可以执行一些在静态编译代码中不安全的推测优化。一个典型的例子是静态分派/单态调用(只有一种实现的多态方法)的内联。如果VM看到该方法总是解析到同一个目标,那么就会执行此操作。曾经复杂的调用被简化为几个CPU指令,由现代CPU进行预测和流水线处理。当保护条件不再成立时,VM可以采取不同的代码路径或甚至回退到解释模式。根据统计数据和程序工作负载,在不同时间生成的机器代码可能不同。这些优化中的许多依赖于程序执行期间收集的信息,如果你在加载类时只编译一次,则无法实现这些优化。
这就是为什么在基准测试算法时需要预热JVM并模拟现实工作负载(偏斜数据可能导致对优化的不切实际的评估)。其他优化包括锁消除、自适应自旋锁、逃逸分析和堆栈分配等。
尽管如此,HotSpot只是众多虚拟机之一。JRockit、Azul、IBM的J9和可重置RVM - 都有不同的性能特征。