关于 HotSpot JVM JIT 的困惑

问题描述 投票:0回答:2

例如,方法中循环10000次。当运行1000次时,backedge_counter会触发

JIT
编译。并且解释器继续执行。当循环4000次时,
JIT
编译完成。

我的问题是,剩余的6000次是如何由解释器执行,或者执行本机代码?或者直到下次调用该方法才执行本机代码? 下次调用这个方法时会发生什么?

java jvm jit jvm-hotspot
2个回答
9
投票
假设您询问的是 HotSpot JVM,答案是剩余的交互将在

已编译代码中执行。

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

http://openjdk.java.net/groups/hotspot/docs/HotSpotGlossary.html

堆栈替换 也称为“OSR”。转换的过程 将堆栈帧解释为已编译的(或更多) 优化)堆栈框架。当口译员发现 一个方法正在循环,要求编译器生成一个特殊的 nmethod 在循环中的某处有一个入口点(具体来说,在 向后分支),并将控制权转移给该方法。粗略 与去优化相反。

如果您使用

-XX:+PrintCompilation

 标志运行 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 条目。


2
投票
让我们重申一下问题:

Java HotSpot 编译器是否能够在执行过程中将方法从解释更改为编译?

我觉得可以。

对于引擎来说,这项任务并不容易(几年前,我在为 PalmOS 手持设备开发名为

JUMP 的提前编译器时积累了一些该领域的经验)。当引擎决定切换时,至少必须考虑以下几点:

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

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

所以我阅读了

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

因此Java HotSpot VM必须能够动态去优化 (然后重新优化,如有必要)先前优化的热点, 即使在执行热点代码时也是如此。

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

编辑:

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

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

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

例如之后HotSpot 编译器已经优化了该方法 4000 次迭代。然后会发生什么?

有两个方面,一琐碎一复杂:

  • 最简单的一点是,循环内发生的调用(例如

    doSomething()

    )将在其编译版本可用时立即调用它。我在原来的答案中没有提到这一点,因为我认为这是理所当然的。

  • 复杂的方面是:当前运行的

    loop()

    执行会在i=4000时从解释代码切换到编译代码吗?这就是我所理解的OP的问题。

© www.soinside.com 2019 - 2024. All rights reserved.