简体   繁体   English

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

[英]Java compiler optimization for repeated method calls?

Does the java compiler (the default javac that comes in JDK1.6.0_21) optimize code to prevent the same method from being called with the same arguments over and over? java编译器(JDK1.6.0_21中的默认javac)是否会优化代码以防止使用相同的参数一遍又一遍地调用相同的方法? If I wrote this code: 如果我写了这段代码:

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

Would the method foo(bar) only run once? 方法foo(bar)只会运行一次吗? If so, is there any way to prevent this optimization? 如果是这样,有什么方法可以阻止这种优化吗? (I'm trying to compare runtime for two algos, one iterative and one comparative, and I want to call them a bunch of times to get a representative sample) (我试图比较运行时的两个算法,一个迭代和一个比较,我想多次调用它们来获得一个代表性的样本)

Any insight would be much appreciated; 任何见解都会非常感激; I took this problem to the point of insanity (I though my computer was insanely fast for a little while, so I kept on adding method calls until I got the code too large error at 43671 lines). 我把这个问题带到了精神错乱的地步(虽然我的计算机在一段时间内非常快,所以我继续添加方法调用,直到我在43671行获得code too large错误)。

The optimization you are observing is probably nothing to do with repeated calls ... because that would be an invalid optimization. 您正在观察的优化可能与重复调用无关......因为这将是无效的优化。 More likely, the optimizer has figured out that the method calls have no observable effect on the computation. 更有可能的是,优化器已经发现方法调用对计算没有可观察到的影响。

The cure is to change the method so that it does affect the result of computation ... 治愈方法是改变方法,以免影响计算结果......

It doesn't; 它没有; that would cause a big problem if foo is non-pure (changes the global state of the program). 如果foo是非纯的,那将导致一个大问题(改变程序的全局状态)。 For example: 例如:

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

You haven't provided enough information to allow for any definitive answers, but the jvm runtime optimizer is extremely powerful and does all sorts of inlining, runtime dataflow and escape analysis, and all manner of cache tricks. 您没有提供足够的信息来允许任何明确的答案,但jvm运行时优化器非常强大,并且可以执行各种内联,运行时数据流和转义分析以及各种缓存技巧。

The end result is to make the sort of micro-benchmarks you are trying to perform all but useless in practice; 最终的结果是制作你试图在实践中完成无用的微基准测试; and extremely difficult to get right even when they are potentially useful. 即使它们具有潜在用途,也很难做到正确。

Definitely read http://www.ibm.com/developerworks/java/library/j-benchmark1.html for a fuller discussion on the problems you face. 绝对阅读http://www.ibm.com/developerworks/java/library/j-benchmark1.html,以便更全面地讨论您遇到的问题。 At the very least you need to ensure: 至少你需要确保:

  1. foo is called in a loop that runs thousands of times foo在循环中调用,运行数千次
  2. foo() returns a result, and foo()返回一个结果,和
  3. that result is used 结果被使用

The following is the minimum starting point, assuming foo() is non-trivial and therefore is unlikely to be inlined. 以下是最小起点,假设foo()非常重要,因此不太可能内联。 Note: You still have to expect loop-unrolling and other cache level optimizations. 注意:您仍然需要进行循环展开和其他缓存级别优化。 Also watch out for the hotspot compile breakpoint (I believe this is ~5000 calls on -server IIRC), which can completely stuff up your measurements if you try to re-run the measurements in the same JVM. 还要注意热点编译断点(我相信这是@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);
    }
}

Seriously, you need to do some reading before you can make any meaningful progress towards writing benchmarks on a modern JVM. 说真的,你需要做一些阅读才能在现代JVM上编写基准测试方面取得任何有意义的进展。 The same optimizations that allows modern Java code to match or even sometimes beat C++ make benchmarking really difficult. 允许现代Java代码匹配甚至有时超过C ++的相同优化使得基准测试变得非常困难。

The Java compiler is not allowed to perform such optimizations because method calls very likely cause side effets, for example IO actions or changes to all fields it can reach, or calling other methods that do so. 不允许 Java编译器执行此类优化,因为方法调用很可能导致副作用,例如IO操作或对其可以到达的所有字段的更改,或调用其他方法。

In functional languages where each function call is guaranteed to return the same result if called with the same arguments (changes to state are forbidden), a compiler might indeed optimize away multiple calls by memorizing the result. 在函数式语言中,如果使用相同的参数调用(对状态的更改被禁止),则保证每个函数调用返回相同的结果,编译器可能确实通过记忆结果来优化多个调用。

If you feel your algorithms are too fast, try to give them some large or complicated problem sets. 如果您觉得算法太快,请尝试为它们提供一些大型或复杂的问题集。 There are only a few algorithms which are always quite fast. 只有少数算法总是非常快。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM