Does use of final keyword in Java improve the performance?

前端 未结 13 1226
粉色の甜心
粉色の甜心 2020-11-22 08:42

In Java we see lots of places where the final keyword can be used but its use is uncommon.

For example:

String str = \"abc\";
System.ou         


        
13条回答
  •  野趣味
    野趣味 (楼主)
    2020-11-22 09:06

    I am amazed that no one has actually posted some real code that is de-compiled to prove that there is at least some minor difference.

    For the reference this has been tested against javac version 8, 9 and 10.

    Suppose this method:

    public static int test() {
        /* final */ Object left = new Object();
        Object right = new Object();
    
        return left.hashCode() + right.hashCode();
    }
    

    Compiling this code as it is, produces the exact same byte code as when final would have been present (final Object left = new Object();).

    But this one:

    public static int test() {
        /* final */ int left = 11;
        int right = 12;
        return left + right;
    }
    

    Produces:

       0: bipush        11
       2: istore_0
       3: bipush        12
       5: istore_1
       6: iload_0
       7: iload_1
       8: iadd
       9: ireturn
    

    Leaving final to be present produces:

       0: bipush        12
       2: istore_1
       3: bipush        11
       5: iload_1
       6: iadd
       7: ireturn
    

    The code is pretty much self-explanatory, in case there is a compile time constant, it will be loaded directly onto the operand stack (it will not be stored into local variables array like the previous example does via bipush 12; istore_0; iload_0) - which sort of makes sense since no one can change it.

    On the other hand why in the second case the compiler does not produce istore_0 ... iload_0 is beyond me, it's not like that slot 0 is used in any way (it could shrink the variables array this way, but may be Im missing some internals details, can't tell for sure)

    I was surprised to see such an optimization, considering how little ones javac does. As to should we always use final? I'm not even going to write a JMH test (which I wanted to initially), I am sure that the diff is in the order of ns (if possible to be captured at all). The only place this could be a problem, is when a method could not be inlined because of it's size (and declaring final would shrink that size by a few bytes).

    There are two more finals that need to be addressed. First is when a method is final (from a JIT perspective), such a method is monomorphic - and these are the most beloved ones by the JVM.

    Then there are final instance variables (that must be set in every constructor); these are important as they will guarantee a correctly published reference, as touched a bit here and also specified exactly by the JLS.


    That being said : there is one more thing that is invisible to every single answer here: garbage collection. It is going to take a lot of time to explain, but when you read a variable, a GC has a so-called barrier for that read. Every aload and getField is "protected" via such a barrier, a lot more details here. In theory, final fields do not need such a "protection" (they can skip the barrier entirely). So if a GC does that - final will improve performance.

提交回复
热议问题