Skip to content
Advertisement

Does final variables occupy memory on a per-instance basis?

I have read other question-answers regarding final instance variables and i came to knew that non-static final instance variables are created in heap for every instance of the class but in java -the complete reference by herbert schildt it is said that :

Variables declared as final do not occupy memory on a per-instance basis .thus, a final variable is essentially a constant

Which is correct?

Advertisement

Answer

The first statement is correct … though limited to final fields of instances.

The second statement is incorrect.

A final variable will occupy memory somewhere at runtime. However where that memory is depends on the kind of variable that you declare as final.

  • If the variable is a local variable or a method’s formal argument variable, then the memory cell will be on the stack.

  • If the variable is a non-static field, then the memory cell will be part of an object, and will be in the heap.

  • If the variable is a static field, then the location of the memory cell will be implementation dependent. (It could be in the heap, or it could be somewhere else.)

It should be noted that some (but not all!) kinds of static final fields are compile constants, and their values are effectively inlined by the compiler. But even when that happens, there will still be an actual field that occupies a memory cell at runtime, and the contents of that memory cell can be accessed reflectively.

(Indeed, you can even modify a final field reflectively. When you do that, the behavior is not specified by the JVM spec, and can be rather surprising in some cases.)


Does final variables occupy memory on a per-instance basis?

No, because:

  • static variables don’t “occupy memory on a per-instance” whether or not they are final.
  • local variables and parameters can be final too, and they don’t “occupy memory on a per-instance”

Can this assumption be made by the compiler if final variables are initialized at their declaration itself and allocate memory to it only one time because obviously every instance created will have the same value for that final variable. Is compiler smart enough to do this kind of optimization?

Consider this

public class Test
    public static test(final int val) {
        System.out.println(val);
    }
}

Now val is final, but its value depends on how you call test method. That is not known at (javac) compile time, and typically it is not known to the JIT compiler either. Indeed, assuming that test is called with different parameters, you can’t directly optimize away the val memory cell.

The same applies to every case apart from static final variables that qualify as compile-time constants (as per the JLS definition).

It is theoretically possible that the JIT compiler could see that Test.test is only ever called with the same constant value, and inline that value into the native code so that no memory cell is needed. However, that optimization has minimal performance benefit, and is unlikely to be applicable in real-life code. So I doubt that it is worth implementing it.

(It is more likely for val to be optimized away due to inlining the body of test into its call site. That is a more general optimization an is definitely worthwhile. That may then allow the peephole optimizer to deduce that val is not needed in the inlined code.)

Advertisement