【问题标题】:How does array access affect the performance?数组访问如何影响性能?
【发布时间】:2017-07-21 19:19:55
【问题描述】:
int steps = 256 * 1024 * 1024;
int[] a = new int[2];

// Loop 1
for (int i=0; i<steps; i++) { a[0]++; a[0]++; }

// Loop 2
for (int i=0; i<steps; i++) { a[0]++; a[1]++; }

谁能解释为什么第二个循环比第一个慢 20 倍(19 毫秒 vs 232 毫秒)?

我就是这样计时的:

long start_time = System.currentTimeMillis();

// Loop

long end_time = System.currentTimeMillis();
System.out.println(end_time - start_time);

【问题讨论】:

  • 看看字节码,第一个可能已经完全优化了
  • 如果您在完整的 MVCE 中提供您的时序代码会有所帮助。
  • 其实我只是对它进行了计时(System.currentTimeMillis() 在每个循环之前、之间和之后),并大致了解了他们做了什么。
  • 你计时了多少次?您应该至少进行 10.000 次迭代,以确保获得准确的数字
  • 计时 20 次,每次迭代的两次计时几乎完全相同

标签: java algorithm performance


【解决方案1】:

总结

JIT 编译器将第一个循环转换为乘法,但没有对第二个循环进行太多优化。

讨论

两个循环的字节码基本相同(可以通过javap -c test.class查看)。

在 Java 中,字节码由 JIT 编译器转换为 x86 指令,该编译器能够执行额外的优化。

如果您有 hsdis 插件,您实际上可以通过 java -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly ... 查看 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

在这种情况下,它发现它实际上可以通过使用乘法在一次通过中实现循环的多次迭代!这解释了第一个循环如何比第二个循环快一个数量级。

【讨论】:

  • 你能进一步解释结论吗?究竟有什么区别?为什么这与速度等有关。我认为这对 OP 的帮助不仅仅是向他展示他可能从未见过的东西。
猜你喜欢
  • 2012-06-25
  • 1970-01-01
  • 1970-01-01
  • 2019-05-01
  • 1970-01-01
  • 2013-04-12
  • 1970-01-01
  • 1970-01-01
  • 2016-02-03
相关资源
最近更新 更多