【发布时间】:2016-02-23 20:26:39
【问题描述】:
我用 java for 循环做了一些运行时测试,发现了一个奇怪的行为。 对于我的代码,我需要原始类型(如 int、double 等)的包装器对象,以模拟 io 和输出参数,但这不是重点。 只要看我的代码。具有字段访问权限的对象如何比原始类型更快?
for 带有原始类型的循环:
public static void main(String[] args) {
double max = 1000;
for (int j = 1; j < 8; j++) {
double i;
max = max * 10;
long start = System.nanoTime();
for (i = 0; i < max; i++) {
}
long end = System.nanoTime();
long microseconds = (end - start) / 1000;
System.out.println("MicroTime primitive(max: ="+max + "): " + microseconds);
}
}
结果:
MicroTime 原语(最大值:=10000.0):110
MicroTime 原语(最大值:=100000.0):1081
MicroTime 原语(最大值:=1000000.0):2450
MicroTime 原语(最大值:=1.0E7):28248
MicroTime 原语(最大值:=1.0E8):276205
MicroTime 原语(最大值:=1.0E9):2729824
MicroTime 原语(最大值:=1.0E10):27547009
for 简单类型的循环(包装对象):
public static void main(String[] args) {
HDouble max = new HDouble();
max.value = 1000;
for (int j = 1; j < 8; j++) {
HDouble i = new HDouble();
max.value = max.value*10;
long start = System.nanoTime();
for (i.value = 0; i.value <max.value; i.value++) {
}
long end = System.nanoTime();
long microseconds = (end - start) / 1000;
System.out.println("MicroTime wrapper(max: ="+max.value + "): " + microseconds);
}
}
结果:
MicroTime 包装器(最大值:=10000.0):157
MicroTime 包装器(最大值:=100000.0):1561
MicroTime 包装器(最大值:=1000000.0):3174
MicroTime 包装器(最大值:=1.0E7):15630
MicroTime 包装器(最大值:=1.0E8):155471
MicroTime 包装器(最大值:=1.0E9):1520967
MicroTime 包装器(最大值:=1.0E10):15373311
迭代次数越多,第二个代码越快。但为什么?我知道 java 编译器和 jvm 正在优化我的代码,但我从没想过原始类型会比具有字段访问权限的对象慢。
有人对此有合理的解释吗?
编辑: HD双班:
public class HDouble {
public double value;
public HDouble() {
}
public HDouble(double value) {
this.value = value;
}
@Override
public String toString() {
return String.valueOf(value);
}
}
我还用其中的代码测试了我的循环。例如,我计算总和 - > 相同的行为(差异不是那么大,但我认为原始算法必须快得多?)。首先我想,计算需要很长时间,字段访问几乎没有区别。
包装器for循环:
for (i.value = 0; i.value <max.value; i.value++) {
sum.value = sum.value + i.value;
}
结果:
MicroTime 包装器(最大值:=10000.0):243
MicroTime 包装器(最大值:=100000.0):2805
MicroTime 包装器(最大值:=1000000.0):3409
MicroTime 包装器(最大值:=1.0E7):28104
MicroTime 包装器(最大值:=1.0E8):278432
MicroTime 包装器(最大值:=1.0E9):2678322
MicroTime 包装器(最大值:=1.0E10):26665540
原始 for 循环:
for (i = 0; i < max; i++) {
sum = sum + i;
}
结果:
MicroTime 原语(最大值:=10000.0):149
MicroTime 原语(最大值:=100000.0):1996
MicroTime 原语(最大值:=1000000.0):2289
MicroTime 原语(最大值:=1.0E7):27085
MicroTime 原语(最大值:=1.0E8):279939
MicroTime 原语(最大值:=1.0E9):2759133
MicroTime 原语(最大值:=1.0E10):27369724
【问题讨论】:
-
我建议将一些实时代码放入循环中。空循环在实际程序中很少见,甚至在严肃的基准测试中也很少见,因此对它们的优化可能不是非常一致或经过良好测试。
-
你能显示
HDouble的代码吗? -
我编辑了我的帖子并添加了Hdouble的代码;)
-
在我使用 jdk1.8.0_45_x84 的机器上,第二个循环比第一个慢大约 3 倍。
-
这样的测试的问题在于它们不是很准确。您正在测量某种 jvm 性能,但不一定在优化后代码比较如何,因为直到运行时才会发生这种情况。 stackoverflow.com/questions/504103/… 测试之间的系统负载也会产生影响等,因此您需要重复测试。最终运行时间更长的测试可能有意义。尽管 JVM 对代码的重写如此之多,以至于很难说它做了什么以及为什么。
标签: java for-loop optimization jvm javacompiler