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

问题描述 投票:0回答:4

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
错误)。

java optimization compiler-optimization method-call
4个回答
6
投票

您观察到的优化可能与重复调用无关……因为那将是无效的优化。 更有可能的是,优化器发现方法调用对计算没有明显的影响。

解决办法就是改变方法,使其确实影响计算结果...


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

4
投票

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

最终结果是你尝试执行的那种微基准在实践中几乎毫无用处;即使它们可能有用,但要正确使用也极其困难。

请务必阅读 http://www.ibm.com/developerworks/java/library/j-benchmark1.html,以获得有关您面临的问题的更全面的讨论。 至少你需要确保:

  1. foo 在运行数千次的循环中被调用
  2. foo() 返回结果,并且
  3. 使用该结果

以下是最小起点,假设 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++ 的相同优化使得基准测试变得非常困难。


0
投票

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

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

如果您觉得您的算法太快,请尝试给他们一些或复杂的问题集。只有少数算法总是相当快。

© www.soinside.com 2019 - 2024. All rights reserved.