在finalize期间引用对象

时间:2009-06-16 16:25:05

标签: java garbage-collection finalizer

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

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

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

5 个答案:

答案 0 :(得分:12)

该对象不是垃圾回收。这被称为“物体复活”。

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

答案 1 :(得分:9)

如果你绝对必须复活对象,这篇JavaWorld文章建议创建一个新的实例,而不是复活正在最终确定的实例,因为如果最终确定的实例有资格再次收集它,它将被简单地收集(终结者赢了'再次运行。)

答案 2 :(得分:6)

这种事情是为什么不鼓励使用finalize()的原因。

答案 3 :(得分:2)

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

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

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

答案 4 :(得分:1)

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

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

如果在finalize()方法中抛出异常(例如由NullPointerException bar null导致{{1}}),则终结过程将终止。

N.B。正如其他人指出的那样......你的例子肯定是值得避免的。