I have been, without a question, using the final
keyword for years to denote fields that should not change for the lifetime of an instance/class. Suddenly this occured to me...
So given this example:
public class TestFinalGC{
private TestFinalGC(){}
private final Object obj = new Object();
public static void main(String []args){
TestFinalGC instance = new TestFinalGC();
// instance Ref -> actual instance ->? obj ref-> actual obj
System.out.println(instance.obj);
instance = null;
//say GC makes sweep here... what happens?
//lets assume theres more code, obj would obviously be eligible for GC on app exit.
}
}
How does the obj
member NOT leak here? Are final
fields automatically WeakReferences such that if the strong references to parent(s) are nulled, they are eligible for garbage collection?
The JLS does not seem to note anything special about final
Update:
So this question of mine was founded on the premise that "reachability" and strong/weak references are closely related. There is this confusing oracle doc on reachability that leads me to believe that nested references should always be "strongly reachable". Hence, I do null my nested object references in all my objects, but it appears that this obviously should not be the case from all of the comments I am receiving.
So regarding "reachability", then, is it simply just that nested object references are no longer considered "reachable" if parent references are no longer reachable?
It could be is true that the premise of this problem is incorrect, but there is still intriguing information to consolidate here.
As Makoto suggested, there is simply nothing special about final
in variable declarations as far as GC is concerned. In your example code
private final Object obj = new Object();
will be garbage collected at the same time as
private Object obj = new Object();
Both are strong references, but are invalidated and garbage collected together with their parent class TestFinalGC
instance. That is because when the instance is GC'd, the reference fields are destroyed as well and the references do not exist any more. obj's reference count thus decreases by one.
However, should you write something like
Object x = myTestFinalGC.obj; // only works if your obj is not private, of course
Then the object will not be garbage collected because it will still have one reference lingering around (assuming this particular line of code is in another class instance that remains alive when myTestFinalGC is garbage collected.
tl;dr: memory allocations are garbage collected when their hard reference count drops to zero (and the collector runs, of course). final
doesn't change this fact.