Question

Are objects that are member of another object become eligible for Garbage Collection when the parent object does? For example, let's imagine this scenario:

Code for MyClass_1:

public class MyClass_1 {

    // Member object
    private MyClass_2 myClass_2;

    // Getter
    public MyClass_2 getMyClass_2() {
        return this.myClass_2;
    }

    // Setter
    public void setMyClass_2(MyClass_2 myClass_2) {
        this.myClass_2 = myClass_2;
    }
}

Code for MyClass_2:

public class MyClass_2 {

    // Member object
    private MyClass_3 myClass_3;

    // Getter
    public MyClass_3 getMyClass_3() {
        return this.myClass_3;
    }

    // Setter
    public void setMyClass_3(MyClass_3 myClass_3) {
        this.myClass_3 = myClass_3;
    }
}

Ok, now we do (code for MyClass_3 is not relevant):

// Instantiation of one root object
MyClass_1 object_1 = new MyClass_1();

// Composition of two more objects
object_1.setMyClass_2(new MyClass_2());
object_1.getMyClass_2().setMyClass_3(new MyClass_3());

// And now...
object_1 = null;

Surely, at this point object_1 is Garbage Collectable, but what about object_2 and object_3? Should I have to do this to avoid a memory leak?

object_1.getMyClass_2().setMyClass_3(null);
object_1.setMyClass_2(null);
object_1 = null;

Or does JVM do that reference release automatically? In case of being necessary to do it manually, can I rely on finalize() for this purpose?

Était-ce utile?

La solution

This is a classic example of island of isolation.

Yes.. All the objects marked null as well as object island (objects referring to each other); but none of them is reachable) get garbage collected.

See this nice post on "Island of isolation" of Garbage Collection

And in this case, you do not need to explicitly set My_class2 and My_class3 as null. Once parent is null, GC will recycle them as well.

Finalize is not a way to do garbage collection. Basically finalize gives you a chance to do something, when the object of that class is being garbage collected. But even do not rely on finalize method for any cleanup, because it's possible that an object never gets garbage collected and thus finalize is never called.

See more about finalize When is the finalize() method called in Java?

Autres conseils

To understand when an object will be garbage collected, you need to understand a bit about how objects are allocated.

All programs have two parts of memory; the stack and the heap. As the program executes, it will enter new functions or methods - this creates a new scope. Whenever a new scope is created, a corresponding new 'frame' is placed on 'top' of the stack. This frame has references to all the variables being used in that scope.

When an object is created, such as via the new keyword (MyObject obj = new MyObject();), a part of memory is set aside on the heap for that object to occupy. The current stack frame will then have a reference to where in the heap the object is living.

That object, obviously, may have references to other objects on the heap. The way the program knows how to get to these objects is by moving from the reference on the stack to the first object on the heap, and then to any other objects connected directly or indirectly. All these objects are on the heap.

When the stack frame is unloaded (which happens when the program leaves that scope), any references held by that frame are released. This may mean that one or more objects on the heap no longer are referenced either directly or indirectly by anything on the stack. These are the objects that are available for garbage collection. If you want to know whether an object will be garbage collected, you simply have to ask whether it is currently connected to the stack.

Note that such objects are available for garbage collection, not automatically garbage collected. Any objects so marked will be torn down at a time of the collector's choosing. Possibly never. finalize() is run on any object being collected: this can ensure certain things happen when it's collected, but given that you can't guarantee it ever is, the usefulness is limited.

Now, for an example:

public void A() {//entering this method creates a new stack frame
  MyObject obj = new MyObject();//'obj' is a reference belonging to the current stack frame.
    //the obj reference is now pointing to a place in memory on the heap

  this.B();
}

public void B() { //Now we are in a new stack frame on top of the older one.
  obj.doSomething();//Doesn't work! There is no 'obj' reference in this stack frame
    //This results in a null pointer exception
  MyObject obj2 = new MyObject();//A totally new object is created on the heap!
} //When we leave this method we leave the scope, and the stack frame. 
 //obj2 is no longer referenced, and so is available for garbage collection

One final note; let us say you instantiate three objects; A, B, and C. C is passed to A and B and saved as a member variable of those objects. Now lets say that you leave the scope where B is defined. C is not garbage collected, because A still has a reference to it; there is still some place on the stack that is holding on to something that is holding on to C.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top