Java compiler optimization for repeated method calls?

孤街醉人 提交于 2019-12-05 06:16:34

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). 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.

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. At the very least you need to ensure:

  1. foo is called in a loop that runs thousands of times
  2. foo() returns a result, and
  3. that result is used

The following is the minimum starting point, assuming foo() is non-trivial and therefore is unlikely to be inlined. 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.

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. The same optimizations that allows modern Java code to match or even sometimes beat C++ make benchmarking really difficult.

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.

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!