In the code below, given that amethod
has been called. At what point/line is the Object originally referenced by myObject
, eligible for Garbage Col
From Book OCA Java SE 7
An object is marked as eligible to be garbage collected when it can no longer be accessed, which can happen when the object goes out of scope. It can also happen when an object’s reference variable is assigned an explicit null value or is reinitialized.
This is actually addressed precisely by the Java Language Specification, §12.6.1, Implementing Finalization :
Optimizing transformations of a program can be designed that reduce the number of objects that are reachable to be less than those which would naively be considered reachable. For example, a Java compiler or code generator may choose to set a variable or parameter that will no longer be used to
null
to cause the storage for such an object to be potentially reclaimable sooner.Another example of this occurs if the values in an object's fields are stored in registers. The program may then access the registers instead of the object, and never access the object again. This would imply that the object is garbage. …
But
… Note that this sort of optimization is only allowed if references are on the stack, not stored in the heap.
For example, consider the Finalizer Guardian pattern:
class Foo { private final Object finalizerGuardian = new Object() { protected void finalize() throws Throwable { /* finalize outer Foo object */ } } }
The finalizer guardian forces
super.finalize
to be called if a subclass overridesfinalize
and does not explicitly callsuper.finalize
.If these optimizations are allowed for references that are stored on the heap, then a Java compiler can detect that the
finalizerGuardian
field is never read, null it out, collect the object immediately, and call the finalizer early. This runs counter to the intent: the programmer probably wanted to call theFoo
finalizer when theFoo
instance became unreachable. This sort of transformation is therefore not legal: the inner class object should be reachable for as long as the outer class object is reachable.
This example can be applied 1:1 to your example, as long as the object is referenced by the instance field classObject
, it can not get garbage collected earlier than the Test
instance containing the reference.
Note, however, that the aggressive optimizations mentioned in the specification are still allowed, when being applied to the code using the Test
instance. The earlier-than-expected collection may happen, as long as both, the Test
instance and the referenced object are collected together. In this case, the following aspect specified in §12.6 applies:
The Java programming language imposes no ordering on finalize method calls. Finalizers may be called in any order, or even concurrently.
So it’s perfectly possible that the Test
instance is collected earlier than the object referenced by classObject
whereas the “inner” object’s finalizer is invoked earlier. The only thing that is guaranteed, is, that when the inner object’s finalizer runs, the outer object is unreachable (or has a pending or concurrent finalization). Since in your example, neither has a non-trivial finalizer, that doesn’t matter anyway…
Your idea that the private object may be GC'd right away because no other code is able to access it does have some traction, but this would mess with the general semantics of Java memory management. For example, if that object implemented finalize
, and Java semantics clearly dictates when an object is eligible for garbage collection, that finalizer method would be have to be called against the specification.
Also note that the object in turn may reference other objects, with even more complicated possible outcomes. Not to mention the object is reachable by Reflection anytime and it would make no sense for the field to be observed to suddenly change to null
even if no code could have made that assignment.
To conclude, there are many reasons why your idea of optimization would not work in the wider picture.
The object will not become a candidate for garbage collection until all references to it are discarded. Java objects are assigned by reference so when you had
classObject = myObject;
You assigned another reference to the same object on the heap. So this line
myObject = null;
Only gets rid of one reference. To make myObject
a candidate for garbage collection, you have to have
classObject = null;
Since you are holding myObject
in classObject
(reference is maintained), it(object in memory referenced through classObject) will not be available for Garbage collection until instance of Test
is freed up/unloaded.
No object is eligible for garbage collection here because you are creating two reference for the same object and you are giving null to only one reference but other reference is still pointing your object