21

如果在 finalize 调用期间保存对当前对象的引用会发生什么?例如:

class foo {
    ...
    public void finalize() {
        bar.REFERENCE = this;
    }
}

对象是否被垃圾收集?当您稍后尝试访问时会发生什么bar.REFERENCE

4

5 回答 5

14

该对象没有被垃圾回收。这被称为“对象复活”。

您必须小心,一旦调用终结器,gc 就不会再次调用它,在.NET 等某些环境中,您可以重新注册终结器,但我不确定 java

于 2009-06-16T16:27:12.727 回答
11

如果您绝对必须复活对象,这篇JavaWorld文章建议创建一个新实例而不是复活正在终结的实例,因为如果正在终结的实例再次符合收集条件,它将被简单地收集(终结器不会再次运行)。

于 2009-06-16T16:53:02.223 回答
7

这种东西finalize()是一般不鼓励使用的原因。

于 2009-06-16T16:30:46.780 回答
2

finalize()方法可以在foo实例上显式调用,也可以由垃圾收集器在尝试回收该对象占用的存储空间时调用。

如果bar是有效实例,则将REFERENCE字段设置为foo实例。从垃圾收集器的角度来看,这增加了foo的引用计数。

如果在方法内部抛出异常finalize()(例如,NullPointerException由于barbeing null),则终结过程简单地终止。

注意正如其他人指出的那样..您的示例绝对是要避免的。

于 2009-06-16T16:47:31.043 回答
2

因为 Java 是一种安全的语言和平台,所以不会释放内存。关联PhantomReference的 s 也不会在他们ReferenceQueue的 s 上排队。VM 只会调用finalize一次对象。JVM Spec 中有一个很好的状态图。

通常,如果您确实使用终结器,则应将声明保留为@Override protected void finalize() throws Throwable,以免干扰 API。最好使用受保护的终结器,如 Effective Java 1st Ed 中。

ClassLoader当普林斯顿大学的一个小组使用它从不受信任的代码构建自定义时,这个特殊的技巧成为头条新闻(无论如何是圣何塞水星) 。尽管规范已经略微收紧(Object构造函数必须在调用终结器之前正常执行 - 在 J2SE 5.0 中指定,在 Java SE 6 中实现),但这仍然是一个问题区域。如果您正在设计一个 API,请确保敏感类不能是子类,以免给自己带来很多麻烦。

于 2009-06-16T20:16:14.400 回答