我为Joshua Bloch的书《有效的Java》找到了this example code。旨在说明为什么应避免不必要地创建对象:
public class Sum {
private static long sum() {
Long sum = 0L;
for (long i = 0; i <= Integer.MAX_VALUE; i++)
sum += i;
return sum;
}
public static void main(String[] args) {
int numSets = Integer.parseInt(args[0]);
long x = 0;
for (int i = 0; i < numSets; i++) {
long start = System.nanoTime();
x += sum();
long end = System.nanoTime();
System.out.println((end - start) / 1_000_000. + " ms.");
}
// Prevents VM from optimizing away everything.
if (x == 42)
System.out.println();
}
}
main方法的最后两行在这里完成了什么?
答案 0 :(得分:2)
最后两行迫使编译器运行整个循环,以找到x
的值。否则,它可能会检测到根本没有使用x
并忽略该循环,因为它内部没有进行任何“实际”工作。即使sum()
被反复调用,但是如果我们对x
不执行任何操作,则最终将舍弃累积其返回值的结果。
当然,这是假定可以安全地忽略循环内的println()
语句,我不确定编译器是否可以做出这样的决定。那将是一个激进的编译器!
答案 1 :(得分:2)
最后的比较是该变量的唯一用法。没有它,谁会关心该变量中的值?
没人!
因此,编译器可能会假设:永远不会使用该值,并且写入该值的代码会产生节点副作用。没用的东西,为什么浪费时间写信给他们。
因此:最终的第一个“读取”用法可防止过度渴望的编译器“优化”对要测量的方法的调用!
答案 2 :(得分:0)
最后两行将确保JVM不会删除它可能会考虑不进行操作的调用,否则,一种选择是使用结果-因此您可以将所有返回值求和,然后在显示总和结束。
防止vm优化的另一种方法是禁用JIT:
-Djava.compiler=NONE
准时:
JVM编译类文件时,它没有完成完整的类 文件;它仅根据需要编译一部分。这样可以避免沉重 完整的源代码解析。这种类型的编译称为 JIT或即时编译。 JVM是平台(OS)依赖的代码 生成JIT是面向平台的,生成本机字节码, 因此它比JVM更快:)