作者:mobiledu2502857177 | 来源:互联网 | 2023-01-28 20:15
1> Peter de Riv..:
摘要
JIT编译器将第一个循环转换为乘法,但不是非常优化第二个循环.
讨论
两个循环的字节码基本相同(您可以查看javap -c test.class
).
在Java中,字节码由JIT编译器转换为x86指令,JIT编译器能够执行其他优化.
java -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly ...
如果你有hsdis插件,你可以实际查看JIT生成的程序集.
我将您添加到每个元素的值更改为0xbad,以便更容易发现相关代码并将循环计数器更改为long
.
第一个循环产生:
mov r11d,dword ptr [r13+10h] Load from memory a[0]
...
add r11d,175ah Add 2 * 0xbad to the value
mov dword ptr [r13+10h],r11d Store to memory a[0]
第二个循环产生:
mov ebx,dword ptr [rax+10h] Load from memory a[0]
add ebx,0badh Add 0xbad
...
mov dword ptr [rax+10h],ebx Store to memory
...
mov ebx,dword ptr [rax+14h] Load from memory a[1]
add ebx,0badh Add 0xbad
...
mov dword ptr [rax+14h],ebx Store to memory a[1]
所以你可以看到编译器已经能够将第一个循环优化为更少的指令.
特别是,它发现相同数组元素的两个加法可以合并为两次加值的单个加法.
当我将循环计数器更改回来时,int
我注意到编译器在第一次循环时设法做得更好:
mov r10d,dword ptr [r14+10h]
imul ecx,r13d,175ah This line converts lots of adds of 0xbad into a single multiply
mov r11d,r10d
sub r11d,ecx
add r10d,175ah
mov dword ptr [r14+10h],r10d
在这种情况下,它发现它可以通过使用乘法实际上在一次传递中实现循环的多次迭代!这解释了第一个循环如何比第二个循环快一个数量级.