In the code below, given that amethod
has been called. At what point/line is the Object originally referenced by myObject
, eligible for Garbage Collection?
class Test {
private Object classObject;
public void amethod() {
Object myObject = new Object();
classObject = myObject;
myObject = null;
}
}
And if classObject
or amethod
had an access modifier of public, protected, default or static, would it affect what point the Object is eligible for Garbage Collection? If so, how would it be affected?
- My first thought is that the Object is eligible for Garbage Collection when the Test object is eligible for Garbage Collection.
- But then again. The optimizer may know that the classObject is never read from in which case
classObject = myObject;
would be optimized out andmyObject = null;
is the point it is eligible for Garbage Collection.
Your question is nonsensical because there is a disconnect between your high-level source code and the low-level representation (global roots in registers, on the stack and in global variables) that the garbage collector sees.
Your phrase "eligible for garbage collection" presumably means at what point does a heap-allocated block of memory become unreachable. So your question can only be answered by making a lot of (dubious) assumptions about what heap allocates and how long the generated code will keep references.
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
You assigned another reference to the same object on the heap. So this line
Only gets rid of one reference. To make
myObject
a candidate for garbage collection, you have to haveNo 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
This is actually addressed precisely by the Java Language Specification, §12.6.1, Implementing Finalization :
But
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 theTest
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, theTest
instance and the referenced object are collected together. In this case, the following aspect specified in §12.6 applies:So it’s perfectly possible that the
Test
instance is collected earlier than the object referenced byclassObject
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.
Since you are holding
myObject
inclassObject
(reference is maintained), it(object in memory referenced through classObject) will not be available for Garbage collection until instance ofTest
is freed up/unloaded.