当前位置: 首页 > 知识库问答 >
问题:

关于热点JVM JIT的困惑

乐欣可
2023-03-14

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

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

共有2个答案

魏成济
2023-03-14

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

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

我认为可以。

这项任务对引擎来说并不容易(几年前我在为PalmOS手持设备开发名为JUMP的超前时间编译器时收集了一些该领域的经验)。当引擎决定切换时,它必须至少考虑以下几点:

>

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

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

    所以我阅读了HotSpot白皮书。它没有明确回答这个问题,但在“去优化”下有一个提示。当一个新类被html" target="_blank">动态加载甚至在调试会话中替换时,以前的优化(如内联)可能会失效。

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

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

    编辑:

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

    我知道有一个方法在执行10000次迭代的循环,如下所示:

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

    在4000次迭代之后,热点编译器优化了该方法。然后会发生什么?

    有两个方面,一个微不足道,一个复杂:

    >

    复杂的方面是:当前运行的循环执行是否会在i=4000时从解释代码切换到编译代码?这就是我所理解的OP的问题。

  • 洪越泽
    2023-03-14

    假设您正在询问热点JVM,答案是剩余的交互将在编译代码中执行。

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

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

    堆栈替换也称为“OSR”。将已解释(或优化程度较低)堆栈帧转换为已编译(或优化程度较高)堆栈帧的过程。当解释器发现一个方法正在循环,请求编译器生成一个特殊的nmethod,该nmethod的入口点位于循环的某个地方(特别是在向后分支),并将控制权转移给该nmethod时,就会发生这种情况。去优化的粗糙逆。

    如果运行带有打印编译标志的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条目。

     类似资料:
    • 当您可以调用递归方法而不是必须将递归方法设置为变量时,是否有一种简单的方法来理解? 例如... 只是调用递归函数遍历: self.recurse(node.left) self.recurse(node.right) 必须将递归函数设置为node。左和右。右: 节点。左=自我。递归(node.left) 节点。右=自我。递归(node.left) 另一个例子是删除bst中的一个节点,你必须将递归函

    • 1.首先,我想确认一下从编程的角度,我们有“静态类型检查”和“动态类型检查,对把? 2.一般情况下我们用typescript做静态类型检查,检查源码里面自定义数据类型,对把? 3.那么,我们做的所谓的动态类型检查是不是指的那些库,比如Joi,ajv什么的,比如你点击一个按钮,然后调这个库来检查一个obj的schema,如果类面的key value类型都能对的上,我们就通过,如果类型对不上,我们就报

    • 本文向大家介绍关于追热点,你是如何考虑的相关面试题,主要包含被问及关于追热点,你是如何考虑的时的应答技巧和注意事项,需要的朋友参考一下 追热点一定需要原则 与内容账号定位相关性,考虑输出内容的可能性大小。 追人热点的风险,涉及版权,时政敏感点。 考虑热点的时效性,常青树热点,短时效性热点 举三个热点例子,二更食堂突破道德底线,吸睛式内容追热点被永久关闭,运营团队解散;7月她刊等大号转载女支教遇害不

    • 问题内容: 在Node.js Express模块​​的代码中,我碰到了这一行,为服务器设置继承: 我不确定这样做是什么- MDC文档(https://developer.mozilla.org/en/JavaScript/Guide/Inheritance_Revisited#prototype_and_ proto )似乎说我可以这样做: 确实,我做了这个测试: 看起来一样吗?所以,是的,我想知

    • 但后者给了我下面的例外。这是为什么? java.lang.StringIndexOutOfBoundsException:String index超出范围:1 java.lang.StringIndexOutOfBoundsException:String index超出范围:1 java.lang.String.charat(String.java:658)在Scala.Collection.i

    • 我无法理解这句话(特别是粗体部分): 类型“指向 cv1 void 的指针”的 prvalue 可以转换为类型为“指向 cv2 T”的 prvalue,其中 T 是对象类型,cv2 是与 cv1 相同的 cv 限定或大于 cv1 的 cv 限定。如果原始指针值表示内存中某个字节的地址 A,并且 A 不满足 T 的对齐要求,则生成的指针值未指定。 我的问题是: > (的地址)指向的地址是否满足 的对