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

前端 未结 5 1765
闹比i
闹比i 2020-12-06 01:07

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 fina

相关标签:
5条回答
  • 2020-12-06 01:44

    In the generated VM opcodes local variables are entries on the operand stack while field references must be moved to the stack via an instruction that retrieves the value through the object reference. I imagine the JIT can make the stack references register references more easily.

    0 讨论(0)
  • 2020-12-06 01:51

    it tells the runtime (jit) that in the context of that method call, those 3 values will never change, so the runtime does not need to continually load the values from the member variable. this may give a slight speed improvement.

    of course, as the jit gets smarter and can figure out these things on its own, these conventions become less useful.

    note, i didn't make it clear that the speedup is more from using a local variable than the final part.

    0 讨论(0)
  • 2020-12-06 01:55

    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.

    0 讨论(0)
  • 2020-12-06 01:57

    The final keyword is a red herring here. The performance difference comes because they are saying two different things.

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

    is saying, "fetch a boolean array, and for each element of that array do something."

    Without final boolean[] used, the function is saying "while the index is less than the length of the current value of the used field of the current object, fetch the current value of the used field of the current object and do something with the element at index i."

    The JIT might have a much easier time proving loop bound invariants to eliminate excess bound checks and so on because it can much more easily determine what would cause the value of used to change. Even ignoring multiple threads, if p.apply could change the value of used then the JIT can't eliminate bounds checks or do other useful optimizations.

    0 讨论(0)
  • 2020-12-06 02:00

    Such simple optimizations are already included in JVM runtime. If JVM does naive access to instance variables, our Java applications will be turtle slow.

    Such manual tuning probably worthwhile for simpler JVMs though, e.g. Android.

    0 讨论(0)
提交回复
热议问题