可以(根据
openjdk version "1.8.0_222"我的分析使用),OpenJDK
12.0.1(根据Oleksandr
Pyrohov)和OpenJDK 13(根据Carlos Heuberger)可靠地复制(或复制,取决于您想要的内容)。
我运行了
-XX:+PrintCompilation足够的时间来获得两种行为的代码,这就是区别。
Buggy实现(显示输出):
--- Previous lines are identical in both 54 17 3 java.lang.AbstractStringBuilder::<init> (12 bytes) 54 23 3 LoopOutPut::test (57 bytes) 54 18 3 java.lang.String::<init> (82 bytes) 55 21 3 java.lang.AbstractStringBuilder::append (62 bytes) 55 26 4 java.lang.AbstractStringBuilder::ensureCapacityInternal (27 bytes) 55 20 3 java.lang.StringBuilder::<init> (7 bytes) 56 19 3 java.lang.StringBuilder::toString (17 bytes) 56 25 3 java.lang.Integer::getChars (131 bytes) 56 22 3 java.lang.StringBuilder::append (8 bytes) 56 27 4 java.lang.String::equals (81 bytes) 56 10 3 java.lang.AbstractStringBuilder::ensureCapacityInternal (27 bytes) made not entrant 56 28 4 java.lang.AbstractStringBuilder::append (50 bytes) 56 29 4 java.lang.String::getChars (62 bytes) 56 24 3 java.lang.Integer::stringSize (21 bytes) 58 14 3 java.lang.String::getChars (62 bytes) made not entrant 58 33 4 LoopOutPut::test (57 bytes) 59 13 3 java.lang.AbstractStringBuilder::append (50 bytes) made not entrant 59 34 4 java.lang.Integer::getChars (131 bytes) 60 3 3 java.lang.String::equals (81 bytes) made not entrant 60 30 4 java.util.Arrays::copyOfRange (63 bytes) 61 25 3 java.lang.Integer::getChars (131 bytes) made not entrant 61 32 4 java.lang.String::<init> (82 bytes) 61 16 3 java.util.Arrays::copyOfRange (63 bytes) made not entrant 61 31 4 java.lang.AbstractStringBuilder::append (62 bytes) 61 23 3 LoopOutPut::test (57 bytes) made not entrant 61 33 4 LoopOutPut::test (57 bytes) made not entrant 62 35 3 LoopOutPut::test (57 bytes) 63 36 4 java.lang.StringBuilder::append (8 bytes) 63 18 3 java.lang.String::<init> (82 bytes) made not entrant 63 38 4 java.lang.StringBuilder::append (8 bytes) 64 21 3 java.lang.AbstractStringBuilder::append (62 bytes) made not entrant
正确运行(无显示):
--- Previous lines identical in both 55 23 3 LoopOutPut::test (57 bytes) 55 17 3 java.lang.AbstractStringBuilder::<init> (12 bytes) 56 18 3 java.lang.String::<init> (82 bytes) 56 20 3 java.lang.StringBuilder::<init> (7 bytes) 56 21 3 java.lang.AbstractStringBuilder::append (62 bytes) 56 26 4 java.lang.AbstractStringBuilder::ensureCapacityInternal (27 bytes) 56 19 3 java.lang.StringBuilder::toString (17 bytes) 57 22 3 java.lang.StringBuilder::append (8 bytes) 57 24 3 java.lang.Integer::stringSize (21 bytes) 57 25 3 java.lang.Integer::getChars (131 bytes) 57 27 4 java.lang.String::equals (81 bytes) 57 28 4 java.lang.AbstractStringBuilder::append (50 bytes) 57 10 3 java.lang.AbstractStringBuilder::ensureCapacityInternal (27 bytes) made not entrant 57 29 4 java.util.Arrays::copyOfRange (63 bytes) 60 16 3 java.util.Arrays::copyOfRange (63 bytes) made not entrant 60 13 3 java.lang.AbstractStringBuilder::append (50 bytes) made not entrant 60 33 4 LoopOutPut::test (57 bytes) 60 34 4 java.lang.Integer::getChars (131 bytes) 61 3 3 java.lang.String::equals (81 bytes) made not entrant 61 32 4 java.lang.String::<init> (82 bytes) 62 25 3 java.lang.Integer::getChars (131 bytes) made not entrant 62 30 4 java.lang.AbstractStringBuilder::append (62 bytes) 63 18 3 java.lang.String::<init> (82 bytes) made not entrant 63 31 4 java.lang.String::getChars (62 bytes)
我们可以注意到一个明显的不同。正确执行后,我们将编译
test()两次。刚开始时,然后又一次(可能是因为JIT注意到该方法有多热)。在越野车中,执行
test()被编译(或反编译)
5 次。
此外,与运行
-XX:-TieredCompilation(这两种解释,或使用
C2) 或
用
-Xbatch(这迫使编译在主线程中运行,而不是平行),输出 保证
,并与30000反复打印出了很多东西,所以
C2编译器似乎成为罪魁祸首。通过运行可以确认这一点
-XX:TieredStopAtLevel=1,它可以禁用
C2也不产生输出(在4级停止再次显示该错误)。
在正确执行中,首先使用3级编译来编译该方法,然后再使用4
级编译。
在越野车执行过程中,先前的编译将被舍弃(
made non entrant),然后再次在Level 3上进行编译(即
C1,请参见前面的链接)。
因此,这绝对是一个错误
C2,尽管我不确定它回到3级编译的事实是否会影响它(以及为什么回到3级,仍然有很多不确定性)。
您可以使用以下代码行生成汇编代码,以更深入地进入兔子孔(另请参阅此内容以启用汇编打印)。
java -XX:+PrintCompilation -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly LoopOutPut > broken.asm
在这一点上,我开始精疲力尽,当放弃以前的编译版本时,越野车的行为开始显现出来,但是我具备90年代的少量组装技能,所以我会让比我聪明的人来使用它从这里。
很可能已经有关于此的错误报告,因为代码是由其他人提供给OP的,并且所有代码C2都没有错误。我希望这种分析对我一样有益。
正如古老的apangin在评论中指出的,这是一个最近的bug。所有有兴趣和乐于助人的人都有义务:)



