When Is The Object Eligible For Garbage Collection

2019-01-08 01:02发布

问题:

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 and myObject = null; is the point it is eligible for Garbage Collection.

回答1:

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;


回答2:

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 overrides finalize and does not explicitly call super.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 the Foo finalizer when the Foo 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…



回答3:

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.



回答4:

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?

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.



回答5:

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.



回答6:

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



回答7:

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.