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

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

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

治愈方法是改变方法,以免影响计算结果……

它没有; 如果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); } } 

您没有提供足够的信息来允许任何确定的答案,但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 ++的相同优化使得基准测试变得非常困难。

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

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

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