1

当父对象这样做时,作为另一个对象成员的对象是否有资格进行垃圾收集?例如,让我们想象一下这种情况:

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;
    }
}

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;
    }
}

好的,现在我们做(MyClass_3 的代码不相关):

// 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;

当然,此时object_1 是 Garbage Collectable,但又如何呢object_2object_3呢?我应该这样做以避免内存泄漏吗?

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

或者 JVM 会自动执行该参考版本吗?如果需要手动完成,我可以依靠 finalize() 来达到这个目的吗?

4

2 回答 2

5

这是孤立岛的典型例子。

是的..所有标记为空的对象以及对象岛(对象相互引用);但它们都无法到达)收集垃圾。

在垃圾收集的“孤立岛”上看到这篇不错的帖子

在这种情况下,您不需要将 My_class2 和 My_class3 显式设置为 null。一旦 parent 为 null,GC 也会回收它们。

Finalize 不是一种进行垃圾收集的方法。基本上,当该类的对象正在被垃圾收集时,finalize 让您有机会做某事。但即使不依赖 finalize 方法进行任何清理,因为对象可能永远不会被垃圾收集,因此永远不会调用 finalize。

查看有关 finalize的更多信息 Java 中何时调用 finalize() 方法?

于 2013-09-13T18:39:10.880 回答
2

要了解对象何时会被垃圾回收,您需要了解一下对象是如何分配的。

所有程序都有两部分内存;堆栈。_ 当程序执行时,它会输入新的函数或方法——这会创建一个新的作用域。每当创建新范围时,都会将相应的新“框架”放置在堆栈的“顶部”。该框架引用了该范围内使用的所有变量。

当一个对象被创建时,例如通过new关键字 ( MyObject obj = new MyObject();),在堆上留出一部分内存供该对象占用。然后,当前堆栈帧将引用对象在堆中的位置。

显然,该对象可能具有对堆上其他对象的引用。程序知道如何获取这些对象的方式是从堆栈上的引用移动到堆上的第一个对象,然后移动到直接或间接连接的任何其他对象。所有这些对象都在堆上。

当堆栈帧被卸载时(当程序离开该范围时发生),该帧持有的任何引用都被释放。这可能意味着堆上的一个或多个对象不再被堆栈上的任何东西直接或间接引用。这些是可用于垃圾收集的对象。如果您想知道一个对象是否会被垃圾回收,您只需询问它当前是否连接到堆栈。

请注意,此类对象可用于垃圾收集,而不是自动进行垃圾收集。任何如此标记的对象将在收藏家选择的时间被拆除。可能永远不会。finalize()在任何正在收集的对象上运行:这可以确保在收集时发生某些事情,但鉴于你不能保证它永远是,有用性是有限的。

现在,举个例子:

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

最后一点;假设您实例化了三个对象;A, B, 和C. C传递给AB保存为这些对象的成员变量。现在假设您离开了B定义的范围。C不是垃圾收集,因为A仍然有它的引用;堆栈上仍有一些地方正在持有正在持有的东西C

于 2013-09-13T19:04:20.007 回答