Java 关于热点JVM JIT的困惑

Java 关于热点JVM JIT的困惑,java,jvm,jit,hotspot,Java,Jvm,Jit,Hotspot,例如,一个方法中有10000次循环。当它运行1000次时,后缘计数器触发JIT编译。解释器继续执行。当它循环4000次时,JIT编译完成 我的问题是,解释器如何执行余数6000次或执行本机代码?或者本机代码在下次调用此方法之前不会执行? 下次调用此方法时会发生什么情况?让我们重申一下这个问题: 是java热点编译器,能够在执行过程中将一个方法从解释的方法编译成编译的? 我想可以 对于引擎来说,这项任务并不容易(几年前,我在为PalmOS掌上电脑开发一个提前编译器时,积累了这方面的一些经验)。当发

例如,一个方法中有10000次循环。当它运行1000次时,后缘计数器触发
JIT
编译。解释器继续执行。当它循环4000次时,
JIT
编译完成

我的问题是,解释器如何执行余数6000次或执行本机代码?或者本机代码在下次调用此方法之前不会执行?
下次调用此方法时会发生什么情况?

让我们重申一下这个问题:

是java热点编译器,能够在执行过程中将一个方法从解释的方法编译成编译的?

我想可以

对于引擎来说,这项任务并不容易(几年前,我在为PalmOS掌上电脑开发一个提前编译器时,积累了这方面的一些经验)。当发动机决定切换时,它必须考虑以下几点,至少:

  • 程序计数器在哪里?在解释代码中,它位于与方法开头的某个字节码偏移处,确切地知道下一步执行哪个字节码。在优化的本机代码中,通常JVM字节码不会转换为孤立的机器指令块,而是相互依赖、无序重新排列等等。因此,切换时可能没有与字节码程序计数器完全对应的本机指令地址

  • 数据在哪里?解释器(可能)将所有内容都保存在堆栈上,优化的本机代码混合使用寄存器和堆栈分配,这对于本机翻译中的不同位置是不同的

所以我读了。它没有明确回答这个问题,但在“去优化”下有一个提示。当动态加载新类或甚至在调试会话中替换新类时,以前的优化(如内联)可能会变得无效

因此,JavaHotSpot虚拟机必须能够动态地去优化 (然后在必要时重新优化)先前优化的热点, 即使在为热点执行代码时也是如此

这也是在编译代码和解释代码之间切换,只是相反。由于这是热点引擎的记录行为,我得出结论,在当前执行的方法调用中,从解释代码转换为编译代码是可能的

编辑:

我对问题的核心理解不够明确

我知道有一种方法可以进行10000次循环,如下所示:

void loop() {
    for (int i=0; i<10000; i++) {
        // example loop body
        objects[i].doSomething();
    }
}
void循环(){

对于(int i=0;i假设您询问的是HotSpot JVM,答案是剩余的交互将在编译的代码中执行

HotSpot JVM有一种称为“堆栈上替换”的技术,可以在方法运行时从解释器切换到编译代码

在堆栈上替换
也称为“OSR”。转换数据的过程 已解释(或优化程度较低)的堆栈帧转换为已编译(或更高)的堆栈帧 优化)堆栈帧。当解释器发现 如果一个方法正在循环,则请求编译器生成一个特殊的 nmethod,在循环的某个地方有一个入口点(特别是在 向后分支),并将控制权转移到该nmethod 与去优化相反

如果使用
-XX:+printcomilation
标志运行JVM,OSR编译将被标记为
%
符号:

    274   27       3       java.lang.String::lastIndexOf (52 bytes)
    275   29       3       java.lang.String::startsWith (72 bytes)
    275   28       3       java.lang.String::startsWith (7 bytes)
    275   30       3       java.util.Arrays::copyOf (19 bytes)
    276   32       4       java.lang.AbstractStringBuilder::append (29 bytes)
    276   31  s    3       java.lang.StringBuffer::append (13 bytes)
    283   33 %     3       LoopTest::myLongLoop @ 13 (43 bytes)
             ^                                    ^
            OSR                            bytecode index of OSR entry
更新

通常在OSR编译之后,常规编译也会排队,以便下次调用该方法时,它将直接以编译模式运行

    187   32 %     3       LoopTest::myLongLoop @ 13 (43 bytes)
    187   33       3       LoopTest::myLongLoop (43 bytes)

但是,如果在再次调用该方法时,常规编译尚未完成,则该方法将在解释器中开始运行,然后在循环中切换到OSR条目。

为什么它不会以本机方式执行?这不是JIT编译的要点吗?+1这是一个有趣的、不平凡的问题,不值得投反对票。Java HotSpot编译器是否能够将当前运行的方法调用从解释代码更改为编译代码?问题的措辞并不完美,因为JIT和HotSpot是微妙不同的方法,但本文明确指出HotSpot的意思。@RalfKleberhoff如果无法更改方法,那么它的意义到底是什么?MaybE它让当前调用完成,但肯定不是接下来的5999次。问题是很微妙的。当然,热点是能够将交换方法从解释到本地的,而这种方法没有执行。这是理所当然的。在方法执行的中间,这也是可能的吗?@拉夫克勒贝霍夫,这不是THA问题。t被问到。这个问题是关于剩下的6000次调用的。我们不要重复这个问题。让我们回答被问到的问题。如果你有你自己的问题,问它,如果你有你自己的问题的答案,贴在那里。坚持重点。但是下次调用这个方法时会发生什么?但是会发生什么下次何时调用此方法?您的回答非常有用。