Java优化:内循环速度不一致?
我和我的朋友都被难住了。在这两段代码中,为什么第一个内循环比第二个内循环快?这是某种 JVM 优化吗?
public class Test {
public static void main(String[] args) {
int[] arr = new int[100000000];
arr[99999999] = 1;
long t1, t2, t3;
for (int ndx = 0; ndx < 10; ndx++) {
t1 = System.currentTimeMillis();
for (int i = 0; i < arr.length; i++)
if (0 < arr[i])
System.out.print("");
t2 = System.currentTimeMillis();
for (int i = 0; i < arr.length; i++)
if (arr[i] > 0)
System.out.print("");
t3 = System.currentTimeMillis();
System.out.println(t2 - t1 +" "+(t3 - t2));
}
}
}
结果:
me@myhost ~ $ java Test
57 80
154 211
150 209
149 209
150 209
150 209
151 209
150 210
150 210
149 209
交换了不等式的顺序:
public class Test {
public static void main(String[] args) {
int[] arr = new int[100000000];
arr[99999999] = 1;
long t1, t2, t3;
for (int ndx = 0; ndx < 10; ndx++) {
t1 = System.currentTimeMillis();
for (int i = 0; i < arr.length; i++)
if (arr[i] > 0)
System.out.print("");
t2 = System.currentTimeMillis();
for (int i = 0; i < arr.length; i++)
if (0 < arr[i])
System.out.print("");
t3 = System.currentTimeMillis();
System.out.println((t2 - t1) +" "+(t3 - t2));
}
}
}
结果:
me@myhost ~ $ java Test
56 80
155 210
150 209
149 209
151 210
149 209
150 209
149 208
149 209
149 208
疯狂:一遍又一遍地做同样的事情,却得到不同的结果。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
简短回答:要避免此问题,请将您正在测试的代码放在单独的方法中。在计时之前,通过调用该方法 11,000 次来预热该方法。这两个将允许 JIT 编译器将方法与编译版本交换。与-server一起运行,它只是更好地调整。使用 System.nanoTime() 来计时。使用以下代码,您将获得一致的测量结果。
长答案:
正如马特在评论中指出的那样,这绝对是“微基准测试”的问题。请参阅Azul 博客。为了支持这一观点,根据我运行程序的方式,我得到以下结果:as -client as -server 并且禁用 JIT 每个设置仅 2 个结果行,其余的类似。
Short answer: To avoid this problem, put the code you are testing in a separate method. Warm up the method by calling it 11,000 times before you time it. These 2 will allow the JIT compiler to swap the method with a compiled version. Run with -server, it's just better tuned. Use System.nanoTime() to time stuff. With the following code you'll get consistent measurements.
Long Answer:
This is definitely a problem of "microbenchmarking" as noted by Matt in the comments. Please see Azul Blog. To support this point of view I am getting the following results depending on how I run the program: as -client as -server and with JIT disabled only 2 result lines per setup, the rest are similar.
我得到不同的结果。我使用的是 Java 1.7.0_02,第二个循环比第一个循环稍快。
尝试使用“javap -l -c Test”命令反汇编类文件并检查差异。对于编译器,我使用的第一个循环包含
ifle
(如果 value <= 0 则分支),而第二个循环包含if_icmpge
(如果 value2 >= value1 则分支)和之前的iconst_0
将 0 加载到堆栈中。I get different results. I'm using Java 1.7.0_02 and the second loop is slightly faster than the first one.
Try using "javap -l -c Test" command to disassemble the class file and check the differences. With the compiler I'm using the first loop contains
ifle
(branch if value <= 0) whereas the second loop containsif_icmpge
(branch if value2 >= value1) andiconst_0
before it to load 0 to the stack.