Jhonny007 Jhonny007 - 2 months ago 24
Java Question

Java final performance/optimization

So I was running some benchmarks on different data structures and noticed, that when I declared my variables final I got 10-20% performance increases.

That really surprised me. I thought the final keyword is purely used for restricting change in variables and optimization would figure out if some variable is of constant value or not.

Here is the example:

import javafx.scene.input.KeyCode;
import java.util.*;

public class Main {
static /*final*/ int LOOPS = Integer.MAX_VALUE / 100;

static /*final*/ KeyCode[] keyCodes = KeyCode.values();

public static void main(String[] args) {
long startTime;
long endTime;

testEnumSet(); //warmup
startTime = System.nanoTime();
testEnumSet();
endTime = System.nanoTime();
System.out.println(" EnumSet: " + (endTime - startTime) + "ns");
}

static /*final*/ EnumSet<KeyCode> enumSet = EnumSet.noneOf(KeyCode.class);
static void testEnumSet() {
for (int i = 0; i < LOOPS; i++) {
/*final*/ KeyCode add = getRandomKeyCode();
if(!enumSet.contains(add)) enumSet.add(add);

/*final*/ KeyCode remove = getRandomKeyCode();
if(enumSet.contains(remove)) enumSet.remove(remove);
}
}

/*final*/ static Random random = new Random();
static KeyCode getRandomKeyCode() {
return keyCodes[random.nextInt(keyCodes.length)];
}
}


With final: ....
EnumSet: 652 266 207ns


Without final:
EnumSet: 802 121 596ns


This is consistently reproducible!

Why is there such an enourmous difference between the code that uses final and the code that doesn't? Why doesn't it get optimized? And why is final faster anyway, what is the difference in the generated bytecode?

Answer

If something can never change, you can do all kinds of inlining optimizations of the actual value instead of looking it up over and over again. This is just one thing you can do that is easy to explain and gives the greatest benefit.

There are many other more esoteric things that happen that have much less impact.

If you look at the bytecode you will see this, especially after the JIT kicks in.

Making the entire class final can have similar benefits.

That said, final references will not always provide measurable gains, it depends on the usage of the reference. In this case EnumSet does a lot of special sauce stuff under the hood if you look at the source. Immutable references probably get inlined as part of that.

Also note that the behavior you are seeing might go away in future release of the JVM, or not be there in other JVM implementations. Anything is subject to change out from under you so don't rely on any one specific implementation.

Here is some more information in greater detail about all the idiomatic uses of final.

Comments