例如,一个方法中有10000次循环。当它运行1000次时,backedge\u计数器触发JIT编译。解释器继续执行。当它循环4000次时,JIT编译完成。
我的问题是,剩余的6000次是如何由解释器执行的,还是如何执行本机代码?或者在下次调用此方法之前不会执行本机代码?下次调用此方法时会发生什么?
让我们重申一下这个问题:
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的问题。
假设您正在询问热点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 的对齐要求,则生成的指针值未指定。 我的问题是: > (的地址)指向的地址是否满足 的对