Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it faster to access final local variables than class variables in Java?

I've been looking at at some of the java primitive collections (trove, fastutil, hppc) and I've noticed a pattern that class variables are sometimes declared as final local variables. For example:

public void forEach(IntIntProcedure p) {
    final boolean[] used = this.used;
    final int[] key = this.key;
    final int[] value = this.value;
    for (int i = 0; i < used.length; i++) {
        if (used[i]) {
          p.apply(key[i],value[i]);
        }
    }
}

I've done some benchmarking, and it appears that it is slightly faster when doing this, but why is this the case? I'm trying to understand what Java would do differently if the first three lines of the function were commented out.

Note: This seems similiar to this question, but that was for c++ and doesn't address why they are declared final.

like image 758
job Avatar asked Jul 06 '11 21:07

job


1 Answers

Accessing local variable or parameter is a single step operation: take a variable located at offset N on the stack. If you function has 2 arguments (simplified):

  • N = 0 - this
  • N = 1 - first argument
  • N = 2 - second argument
  • N = 3 - first local variable
  • N = 4 - second local variable
  • ...

So when you access local variable, you have one memory access at fixed offset (N is known at compilation time). This is the bytecode for accessing first method argument (int):

iload 1  //N = 1

However when you access field, you are actually performing an extra step. First you are reading "local variable" this just to determine the current object address. Then you are loading a field (getfield) which has a fixed offset from this. So you perform two memory operations instead of one (or one extra). Bytecode:

aload 0  //N = 0: this reference
getfield total I  //int total

So technically accessing local variables and parameters is faster than object fields. In practice, many other factors may affect performance (including various levels of CPU cache and JVM optimizations).

final is a different story. It is basically a hint for the compiler/JIT that this reference won't change so it can make some heavier optimizations. But this is much harder to track down, as a rule of thumb use final whenever possible.

like image 136
Tomasz Nurkiewicz Avatar answered Sep 16 '22 22:09

Tomasz Nurkiewicz