使用中间变量而不是 array.length 是否会使 for 循环更快?
Android 文档中的“性能提示”部分有一个非常大胆的声明:
one()
更快。它将所有内容提取到局部变量中,从而避免了查找。只有数组长度才能提供性能优势。
其中它引用了此代码片段:
int len = localArray.length;
for (int i = 0; i < len; ++i) {
sum += localArray[i].mSplat;
}
这让我很惊讶,因为只是访问一个整数,如果你使用一个中间变量,你必须再次执行完全相同的步骤。我们真的是说一个只需要去而不是的中间变量更快吗?localArray.length
x
y.x
我看了一下这个问题,它的想法大致相同,但使用数组列表及其后续方法。在这里,似乎没有区别,因为该方法调用可能只是内联到整数访问(这正是我们在这里的场景)。.size()
所以我拿起字节码,看看它是否能告诉我什么。
给定以下源代码:
public void MethodOne() {
int[] arr = new int[5];
for (int i = 0; i < arr.length; i++) { }
}
public void MethodTwo() {
int[] arr = new int[5];
int len = arr.length;
for (int i = 0; i < len; i++) { }
}
我得到以下字节码:
public void MethodOne();
Code:
0: iconst_5
1: newarray int
3: astore_1
4: iconst_0
5: istore_2
6: iload_2
7: aload_1
8: arraylength
9: if_icmpge 18
12: iinc 2, 1
15: goto 6
18: return
public void MethodTwo();
Code:
0: iconst_5
1: newarray int
3: astore_1
4: aload_1
5: arraylength
6: istore_2
7: iconst_0
8: istore_3
9: iload_3
10: iload_2
11: if_icmpge 20
14: iinc 3, 1
17: goto 9
20: return
它们在以下说明中有所不同:
方法一
6: iload_2
7: aload_1
8: arraylength
9: if_icmpge 18
12: iinc 2, 1
15: goto 6
18: return
方法二
9: iload_3
10: iload_2
11: if_icmpge 20
14: iinc 3, 1
17: goto 9
20: return
现在,我不是100%确定我必须如何解释,但我认为这只是表明您正在访问的领域。第一种方法加载索引计数器和数组并访问字段,而第二种方法加载索引计数器和中间变量。8: arraylength
arraylength
我还用JMH(10次预热,10次迭代,5次分叉)对这两种方法进行了基准测试,这给了我以下基准测试结果:
c.m.m.Start.MethodOne thrpt 50 3447184.351 19973.900 ops/ms
c.m.m.Start.MethodTwo thrpt 50 3435112.281 32639.755 ops/ms
这告诉我,这种差异可以忽略不计,甚至不存在。
Android文档声称在循环条件下使用中间变量是基于什么的?