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,以获得有关您面临的问题的更全面的讨论。 至少你需要确保:
以下是最小起点,假设 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 操作或对其可以到达的所有字段进行更改,或调用其他这样做的方法。
在函数式语言中,如果使用相同的参数调用,每个函数调用都保证返回相同的结果(禁止更改状态),编译器确实可以通过记住结果来优化多次调用。
如果您觉得您的算法太快,请尝试给他们一些大或复杂的问题集。只有少数算法总是相当快。