实时(JIT)编译器引用编译器,该编译器在程序运行时将代码转换为本机代码。通常,它将字节码转换为Java编程语言的机器代码。
通常有两种JIT编译器:基于方法的jit和基于跟踪的jit。前者主要是配置文件运行时程序,只选择热方法进行编译。
我的问题是JIT编译器如何处理类字段成员? _b指的是Heap上新创建的Java对象。那么,当方法'测试(字符串)V'时,JIT编译器如何翻译getField
指令?被选中进行jit编译?这里生成的本机代码和字节码之间是否有jump
来回?
class A{
MyObject _b = new MyObject(..);
public void test(String ars){
aload 0
getField A::_b MyObject
invokvirtual MyObject sayHello (String)V
...
}
}
答案 0 :(得分:0)
HotSpot虚拟机维护一堆方法框架。该堆栈通常包含编译帧和解释帧,具体取决于执行代码的“热度”。
只要字节码程序的语义不改变,就可以从JIT编译的代码以任何方式执行对象分配。如果编译器可以证明该对象从未被使用过,它甚至可以完全避免分配,因为这不会改变所提到的语义。
答案 1 :(得分:0)
您质疑“JIT编译器如何处理类字段成员”,包含两个错误的假设。首先,我们不能讨论“ ”JIT编译器,有很多不同的现有JIT编译器/优化器,即使我们仅限于Oracle JVM的行为,我们也不能做一个全面的陈述。其次,没有单独处理功能,特别是像现场访问一样简单。
目前尚不清楚为什么您认为在执行getfield
指令期间编译代码和解释代码之间存在交互。无论JVM如何实现对象引用,它们都是一种值,读取字段_b
的值只是意味着从内存中读取值。向字段写入值,即对新创建的对象的引用,发生在A
的构造函数中,而不是在读取字段时。并且代码的状态与该内存访问完全无关。
当涉及invokvirtual
指令时,它的执行可能意味着从解释模式到编译代码的变化,反之亦然。但是,这又与前面的getfield
指令无关。如果目标对象引用是aload
指令或前面的方法调用或方法内部的新分配的结果,则不会有所不同。它只取决于被调用方法的代码状态,即MyObject.sayHello
或子类的重写方法。
作为Antimony has pointed out,在编译/优化方法时,生成的代码不太可能在主流CPU上建模堆栈。生成的本机代码不会推送对堆栈的引用,而只是直接读取字段值并将其用于后续调用。引用可能暂时存储到CPU寄存器中,但如果目标CPU可以处理这种间接寻址,则读操作和调用也可能融合到单个指令中。 sayHello
的代码也可能被内联,优化器的整体结果根本没有原始代码的回忆。