用于重复方法调用的Java编译器优化?

时间:2010-08-02 03:13:42

标签: java optimization compiler-construction compiler-optimization method-call

java编译器(JDK1.6.0_21中的默认javac)是否会优化代码以防止使用相同的参数一遍又一遍地调用相同的方法?如果我写了这段代码:

public class FooBar {
    public static void main(String[] args) {
        foo(bar);
        foo(bar);
        foo(bar);
    }
}

方法foo(bar)只运行一次吗?如果是这样,有什么方法可以阻止这种优化吗? (我试图比较运行时的两个算法,一个迭代和一个比较,我想多次调用它们来获得一个代表性的样本)

任何见解都会受到高度赞赏;我把这个问题带到疯狂的程度(虽然我的计算机在一段时间内非常快,所以我一直在添加方法调用,直到我在43671行出现code too large错误。)

4 个答案:

答案 0 :(得分:6)

您正在观察的优化可能与重复调用无关......因为这将是无效的优化。更有可能的是,优化器已经发现方法调用对计算没有可观察到的影响。

治愈方法是改变方法,使其确实影响计算结果......

答案 1 :(得分:4)

没有;如果foo是非纯的(改变程序的全局状态),那将导致一个大问题。例如:

public class FooBar {
    private int i = 0;
    private static int foo() {
        return ++i;
    }

    public static void main(String[] args) {
        foo();
        foo();
        foo();
        System.out.println(i);
    }
}

答案 2 :(得分:3)

您没有提供足够的信息来允许任何明确的答案,但jvm运行时优化器非常强大,可以执行各种内联,运行时数据流和转义分析以及各种缓存技巧。

最终的结果是制作一些你试图在实践中完成无用的微基准测试;即使它们具有潜在用途,也很难做到正确。

绝对阅读http://www.ibm.com/developerworks/java/library/j-benchmark1.html,以便更全面地讨论您遇到的问题。至少你需要确保:

  1. foo在一个运行数千次的循环中被调用
  2. foo()返回结果,
  3. 使用了该结果
  4. 以下是最小起点,假设foo()非常重要,因此不太可能内联。注意:您仍然需要进行循环展开和其他缓存级别优化。还要注意热点编译断点(我相信这是@server IIRC上的〜5000次调用),如果你试图在同一个JVM中重新运行测量,它可以完全填满你的测量。

    public class FooBar {
        public static void main(String[] args) {
            int sum = 0;
            int ITERATIONS = 10000;
            for (int i = 0; i < ITERATIONS; i++) {
                sum += foo(i);
            }
    
            System.out.println("%d iterations returned %d sum", ITERATIONS, sum);
        }
    }
    

    说真的,你需要做一些阅读才能在现代JVM上编写基准测试方面取得任何有意义的进展。允许现代Java代码匹配甚至有时超过C ++的相同优化使得基准测试变得非常困难。

答案 3 :(得分:0)

Java编译器不允许执行此类优化,因为方法调用很可能导致副作用,例如IO操作或对其可以到达的所有字段的更改,或调用其他方法。

在函数式语言中,如果使用相同的参数调用(禁止更改状态),每个函数调用都保证返回相同的结果,编译器可能会通过记忆结果来优化多个调用。

如果您认为算法太快,请尝试为它们提供一些大型或复杂的问题集。只有少数算法总是非常快。