Java Performance: why a method call can be quicker than direct calculations in if conditional and array indexing?
I have the following method in a Java app:
p开发者_StackOverflow中文版ublic void setPixel(int x, int y, int rgb) {
if (isValidPixel(x, y)) {
bitmap[indexOf(x, y)] = rgb;
}
}
When I put direct calculations instead of the method calls, like:
public void setPixel(int x, int y, int rgb) {
if (x < width && y < height) {
bitmap[y * width + x] = rgb;
}
}
the code runs with 4 to 5 milliseconds more than the first. So why?
If your numbers are correct and reproducible, the most probable answer is that the JIT compiler manages to compile the method but gives up on the inline statement. You could disable the JIT compiler to prove the theory.
It is almost certainly the case that you methods are being optimised earlier making the first case look faster.
I suggest you run both benchmarks for at least 2-10 seconds in both orders (try one first, and later second) before trying to draw any conclusions.
I would expect the first case to inline its methods and make it exactly the same as the second.
As leonm posts it is probably JIT compiler issue.
JIT compiler works with your compiled java code (bytecode) and when some part of the code is called often, then it is translated into the binary (machine) code which is even faster than interpreted bytecode.
Bytecode which is chosen to be translated into binary code can be determined by several rules. Some of the rules are your code is in separate very short methods and code within loops.
Problem of this issue is that short methods are usually eligible for translate much earlier than inline code in some larger piece of code or method. Especially if there is no loop or is called rarely.
Don't forget that if you duplicate same inline code in several places it is JIT compiled separately, while short common method is translated preferentially.
If you disable JIT compiler then the java virtual machine compile whole your app into the binary code in startup phase and then should not matter if you call some functionality via method or as direct inline code.
If you want to test performance even with enabled JIT compiler you should perform warm up phase before testing. This warm up indicates JIT compiler that some piece of code is called often and compiler translate it into binary code at the background.
Warm up code might look like this:
public void testSetPixel() {
// warm up
for (int i=0; i < 1000; i++) {
setPixel(i, i, 10);
}
// your regular testing code with testing setPixel(int, int, int) method
...
}
精彩评论