【发布时间】:2012-09-25 08:51:09
【问题描述】:
给出以下(直截了当的)代码:
public class pr1 {
public static void f1(){
long sx = 0, s;
s = System.currentTimeMillis();
for(long i = 0; i < Integer.MAX_VALUE; ++i){
sx += i;
}
System.out.println("f1(): " + (System.currentTimeMillis() - s));
}
public static void f2(){
long sx = 0, s, i;
s = System.currentTimeMillis();
i = Integer.MAX_VALUE;
while(i-->0){
sx+=i;
}
sx += Integer.MAX_VALUE;
System.out.println("f2(): " + (System.currentTimeMillis() - s));
}
public static void f3(){
long sx = 0, s, i;
s = System.currentTimeMillis();
i = Integer.MAX_VALUE;
while(--i>0){
sx+=i;
}
sx += Integer.MAX_VALUE;
System.out.println("f3(): " + (System.currentTimeMillis() - s));
}
public static void f4(){
long sx = 0, s, i;
s = System.currentTimeMillis();
i = Integer.MAX_VALUE;
do{
sx+=i;
}while(--i>0);
System.out.println("f4(): " + (System.currentTimeMillis() - s));
}
public static void main(String args[]){
f1();
f2();
f3();
f4();
}
}
以及运行代码后的实际结果:
f1(): 5828
f2(): 8125
f3(): 3406
f4(): 3781
你能解释一下大的时差吗?从理论上讲,这些循环实现了相同的功能,但在实践中,这四个版本中的每一个似乎都存在相关的时间差。
重复执行后,结果几乎相同。
稍后编辑 作为另一个测试,我重写了 main 方法:
public static void main(String args[]){
for(int i = 0; i < 4; ++i){
f1(); f2(); f3(); f4();
}
}
而新的结果是:
f1(): 5906
f2(): 8266
f3(): 3406
f4(): 3844
f1(): 5843
f2(): 8125
f3(): 3438
f4(): 3859
f1(): 5891
f2(): 8156
f3(): 3406
f4(): 3813
f1(): 5859
f2(): 8172
f3(): 3438
f4(): 3828
10 次重复:
f1(): 5844
f2(): 8156
f3(): 3453
f4(): 3813
f1(): 5844
f2(): 8218
f3(): 3485
f4(): 3937
f1(): 5985
f2(): 8156
f3(): 3422
f4(): 3781
f1(): 5828
f2(): 8234
f3(): 3469
f4(): 3828
f1(): 5844
f2(): 8328
f3(): 3422
f4(): 3859
f1(): 5844
f2(): 8188
f3(): 3406
f4(): 3797
f1(): 5906
f2(): 8219
f3(): 3422
f4(): 3797
f1(): 5843
f2(): 8203
f3(): 3454
f4(): 3906
f1(): 5844
f2(): 8140
f3(): 3469
f4(): 3812
f1(): 5860
f2(): 8109
f3(): 3422
f4(): 3813
去掉循环之间的演算后,结果还是有点不一样:
public class pr2 {
public static void f1(){
long sx = 0, s;
s = System.currentTimeMillis();
for(long i = 0; i < Integer.MAX_VALUE; ++i);
System.out.println("f1(): " + (System.currentTimeMillis() - s));
}
public static void f2(){
long sx = 0, s, i;
s = System.currentTimeMillis();
i = Integer.MAX_VALUE;
while(i-->0);
System.out.println("f2(): " + (System.currentTimeMillis() - s));
}
public static void f3(){
long sx = 0, s, i;
s = System.currentTimeMillis();
i = Integer.MAX_VALUE;
while(--i>0);
System.out.println("f3(): " + (System.currentTimeMillis() - s));
}
public static void f4(){
long sx = 0, s, i;
s = System.currentTimeMillis();
i = Integer.MAX_VALUE;
do{
}while(--i>0);
System.out.println("f4(): " + (System.currentTimeMillis() - s));
}
public static void main(String args[]){
for(int i = 0; i < 2; ++i){
f1(); f2(); f3(); f4();
}
}
}
但是时差还是存在的:
f1(): 3219
f2(): 4859
f3(): 2610
f4(): 3031
f1(): 3219
f2(): 4812
f3(): 2610
f4(): 3062
JVM:
java version "1.6.0_20"
Java(TM) SE Runtime Environment (build 1.6.0_20-b02)
Java HotSpot(TM) Client VM (build 16.3-b01, mixed mode, sharing)
稍后编辑: 对于第一个版本,我为 javac 使用了 -O 参数。新结果是:
f1(): 3219
f2(): 4859
f3(): 2610
f4(): 3031
稍后编辑
好的,我在家里尝试了相同的代码,使用的是 Linux 机器:
java version "1.6.0_18"
OpenJDK Runtime Environment (IcedTea6 1.8) (6b18-1.8-0ubuntu1)
OpenJDK Server VM (build 14.0-b16, mixed mode)
结果是“正常的”。现在没有问题:
f1(): 7495
f2(): 7418
f3(): 7457
f4(): 7384
【问题讨论】:
-
这是可重现的还是单发的?
-
java 中的规则是:JVM 比你聪明,不要试图以智取胜
-
@Andreas_D 可重现。 - 自己尝试代码。
-
@Andrei - 如果我手头有编译器,我会这样做的 ;) - 你能检查 BalusC 的第三个列表项并再试一次吗?没错,看起来后减量比减量前慢得多,但是 - 正如 BalusC 所示,它可能是一个“jvm-optimizing-artifact”
-
f(3)的运行次数比f(2)少一倍,因为在比较之前会递减值。
标签: java performance optimization