为什么这个内循环比通过外循环的第一次迭代快4倍?
我试图重现此处描述的一些处理器缓存效果。我知道Java是一个托管环境,这些例子不会完全翻译,但我遇到了一个奇怪的案例,我试图提炼成一个简单的例子来说明效果:
public static void main(String[] args) {
final int runs = 10;
final int steps = 1024 * 1024 * 1024;
for (int run = 0; run < runs; run++) {
final int[] a = new int[1];
long start = System.nanoTime();
for (int i = 0; i < steps; i++) {
a[0]++;
}
long stop = System.nanoTime();
long time = TimeUnit.MILLISECONDS.convert(stop - start, TimeUnit.NANOSECONDS);
System.out.printf("Time for loop# %2d: %5d ms\n", run, time);
}
}
输出:
Time for loop# 0: 24 ms
Time for loop# 1: 106 ms
Time for loop# 2: 104 ms
Time for loop# 3: 103 ms
Time for loop# 4: 102 ms
Time for loop# 5: 103 ms
Time for loop# 6: 104 ms
Time for loop# 7: 102 ms
Time for loop# 8: 105 ms
Time for loop# 9: 102 ms
内部循环的第一次迭代大约是后续迭代的 4 倍。这与我通常期望的相反,因为通常随着JIT的启动,性能会上升。
当然,在任何严肃的微基准测试中,人们都会做几个预热循环,但我很好奇是什么导致了这种行为,特别是因为如果我们知道环路可以在24ms内执行,那么稳态时间超过100ms并不是很令人满意。
作为参考,我正在使用的JDK(在linux上):
openjdk version "1.8.0_40"
OpenJDK Runtime Environment (build 1.8.0_40-b20)
OpenJDK 64-Bit Server VM (build 25.40-b23, mixed mode)
更新:
以下是一些更新信息,基于一些评论和一些实验:
1) 将 System.out I/O 移出环路(通过将时序存储在大小为“runs”的数组中)不会对时间产生显著差异。
2)上面显示的输出是我从Eclipse中运行时。当我从命令行编译和运行时(使用相同的JDK / JVM),我得到的结果更适度,但仍然很重要(2倍而不是4倍)。这似乎很有趣,因为在日食中运行会减慢速度,如果有的话。
3)向上移动,退出循环,使其被重复使用,每次迭代都没有效果。a
4)如果更改为,则第一次迭代运行得更快(约20%),而其他迭代仍然相同(较慢)的速度。int[] a
long[] a
更新 2:
我认为apangin的答案可以解释它。我用Sun的1.9 JVM尝试了这个,它来自:
openjdk version "1.8.0_40"
OpenJDK Runtime Environment (build 1.8.0_40-b20)
OpenJDK 64-Bit Server VM (build 25.40-b23, mixed mode)
Time for loop# 0: 48 ms
Time for loop# 1: 116 ms
Time for loop# 2: 112 ms
Time for loop# 3: 113 ms
Time for loop# 4: 112 ms
Time for loop# 5: 112 ms
Time for loop# 6: 111 ms
Time for loop# 7: 111 ms
Time for loop# 8: 113 ms
Time for loop# 9: 113 ms
自:
java version "1.9.0-ea"
Java(TM) SE Runtime Environment (build 1.9.0-ea-b73)
Java HotSpot(TM) 64-Bit Server VM (build 1.9.0-ea-b73, mixed mode)
Time for loop# 0: 48 ms
Time for loop# 1: 26 ms
Time for loop# 2: 22 ms
Time for loop# 3: 22 ms
Time for loop# 4: 22 ms
Time for loop# 5: 22 ms
Time for loop# 6: 22 ms
Time for loop# 7: 22 ms
Time for loop# 8: 22 ms
Time for loop# 9: 23 ms
这是相当的改进!