我的朋友和我都很难过.在这两个代码块中,为什么第一个内循环比第二个内循环快?这是某种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,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
精神错乱:一遍又一遍地做同样的事情并得到不同的结果.
最佳答案
简短回答:要避免此问题,请将您正在测试的代码放在单独的方法中.在你计时之前调用它11,000次来预热这个方法.这两个将允许JIT编译器将该方法与编译版本交换.使用-server运行,它只是更好地调整.使用System.nanoTime()计时.使用以下代码,您将获得一致的测量结果.
public class AlphaTest
{
public static void processA(int[] arr)
{
for (int i = 0; i < arr.length; i++)
if (arr[i] > 0)
System.out.print("");
}
public static void processB(int[] arr)
{
for (int i = 0; i < arr.length; i++)
if (0 < arr[i])
System.out.print("");
}
public static void main(String[] args)
{
int[] smallArr = new int[10];
for (int i = 0; i < smallArr.length; i++)
{
smallArr[i] = 1;
}
//warmup
for (int i = 0; i < 11000; i++)
{
processA(smallArr);
processB(smallArr);
}
int[] arr = new int[100000000];
arr[99999999] = 1;
long t1,t3;
for (int ndx = 0; ndx < 10; ndx++)
{
t1 = System.nanoTime();
processA(arr);
t2 = System.nanoTime();
processB(arr);
t3 = System.nanoTime();
System.out.println(((t2 - t1)/1000000L) + " " + ((t3 - t2)/1000000L));
}
}
}
答案很长:
这绝对是Matt在评论中指出的“微基准标记”的问题.请参阅Azul Blog.为了支持这种观点,我得到以下结果取决于我如何运行程序:as -client as -server和JIT禁用每个设置只有2个结果行,其余类似.
java -client -Xms1024m -Xmx1024m Test
272 262
263 252
...
java -server -Xms1024m -Xmx1024m Test
513 173
483 201
...
java -client -Djava.compiler=NONE -Xms1024m -Xmx1024m AlphaTest
2062 1929
2042 2034
...
java -server -Djava.compiler=NONE -Xms1024m -Xmx1024m AlphaTest
1844 1864
1843 1931