在finalize期间引用对象
如果在finalize调用期间保存对当前对象的引用会发生什么? 例如:
class foo { ... public void finalize() { bar.REFERENCE = this; } }
对象是否被垃圾收集? 当您尝试访问bar.REFERENCE
时会发生什么。稍后会bar.REFERENCE
吗?
该对象不是垃圾回收。 这被称为“物体复活”。
你必须小心,一旦调用终结器,gc将不会再次调用它,在.NET等一些环境中你可以重新注册终结器,但我不确定java
如果你绝对必须复活对象,这篇JavaWorld文章建议创建一个新实例而不是复活正在最终确定的实例,因为如果最终确定的实例再次符合收集资格,它将被简单地收集(终结器将不再运行)。
这种事情是为什么通常不鼓励使用finalize()
的原因。
因为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,请确保敏感类不能成为子类并为您节省很多麻烦。
可以在foo
实例上显式调用finalize()
方法,或者当垃圾收集器尝试回收该对象占用的存储时,可以调用它。
如果bar
是有效实例,则它将REFERENCE
字段设置为foo
实例。 从垃圾收集器的角度来看,这会增加foo
的引用计数。
如果在finalize()
方法中抛出exception(例如由于bar
为null
而导致的NullPointerException
),则终结过程将终止。
NB正如其他人所指出的那样……你的例子肯定是值得避免的。