首页 文章

在这段有效Java的示例代码中,JVM是如何阻止'optimizing away everything'的?

提问于
浏览
1

我发现this example code为Joshua Bloch 's book, Effective Java. It' s意味着要证明为什么你应该避免不必要地创建对象:

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();
    }
}

主要方法的最后两行在这里完成了什么?

3 回答

  • 2

    最后的比较是该变量的唯一用法 . 没有它,谁会关心那个变量的 Value ?

    没有人!

    因此,编译器可能会假设:该值永远不会被使用,并且写入它的代码具有节点副作用 . 不习惯的事情,为什么浪费时间写信给他们 .

    因此:最后的第一个“读取”用法可防止过度急切的compilerd“优化”对您要测量的方法的调用!

  • 2

    最后两行强制编译器运行整个循环,以找到 x 的值 . 否则它可能会检测到 x 根本没有被使用而忽略了循环,因为它内部没有"real"工作 . 即使重复调用 sum() ,如果我们对 x 什么都不做,那么累积其返回值的结果最终会被丢弃 .

    当然,这假设循环中的 println() 语句可以安全地忽略,我不确定编译器是否可以做出这样的决定 . 那将是一个积极的编译器!

  • 0

    最后两行将确保JVM不会删除它可能会考虑无操作的调用,否则,一个选项是使用结果 - 因此您可以对所有返回值求和,然后在结尾显示总和 .

    阻止vm优化的另一种方法是禁用JIT:

    -Djava.compiler=NONE
    

    JIT:

    当JVM编译类文件时,它不会完成完整的类文件;它只在需要的基础上编译它的一部分 . 这避免了对完整源代码的大量解析 . 这种类型的编译称为JIT或即时编译 . JVM是依赖于平台(OS)的代码生成JIT是面向平台的,生成本机字节代码,因此它比JVM更快:)

相关问题