最终确定期间对对象的引用
如果在 Finalize 调用期间保存对当前对象的引用,会发生什么情况? 例如:
class foo {
...
public void finalize() {
bar.REFERENCE = this;
}
}
该对象是否被垃圾收集? 当您稍后尝试访问 bar.REFERENCE
时会发生什么?
What happens if you save a reference to the current object during the finalize call? For example:
class foo {
...
public void finalize() {
bar.REFERENCE = this;
}
}
Is the object garbage-collected, or not? What happens when you try to access bar.REFERENCE
later?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
该对象不会被垃圾回收。 这就是所谓的“对象复活”。
你必须小心,一旦调用了终结器,gc就不会再次调用它,在某些环境(例如.NET)上,你可以重新注册终结器,但我不确定java
The object is not garbage collected. This is know as "Object resurrection".
You must be careful with that, once the finalizer is called the gc won't call it again, on some enviroments like .NET you can re-register the finalizer but i'm not sure about java
如果你绝对必须复活对象,这个 JavaWorld文章建议创建一个新实例,而不是复活正在终结的实例,因为如果正在终结的实例再次符合收集条件,它将被简单地收集(终结器不会再次运行)。
If you absolutely must resurrect objects, this JavaWorld article suggests creating a fresh instance rather than resurrecting the instance being finalized because if the instance being finalized becomes eligible for collection again it will simply be collected (the finalizer won't be run again).
这种事情就是为什么通常不鼓励使用
finalize()
的原因。This kind of thing is the reason why the use of
finalize()
is generally discouraged.finalize()
方法可以在foo
实例上显式调用,也可以由垃圾收集器在尝试回收该对象占用的存储空间时调用。如果
bar
是有效实例,则会将REFERENCE
字段设置为foo
实例。 从垃圾收集器的角度来看,这增加了foo
的引用计数。如果在
finalize()
方法内部抛出异常(例如,由于bar
为null
而引发NullPointerException
),那么最终确定过程就简单地终止。注意正如其他人指出的那样..你的例子绝对是应该避免的。
The
finalize()
method may be invoked explicitly on thefoo
instance, or it may be invoked by the garbage collector when it tries to reclaim the storage occupied by that object.If
bar
is a valid instance, it sets theREFERENCE
field to thefoo
instance. From the garbage collector's point of view, this increasesfoo
's reference count.If an exception is thrown inside the
finalize()
method (e.g. such as aNullPointerException
due tobar
beingnull
), then the finalization process simply terminates.N.B. As others have pointed out.. your example is definitely something to be avoided.
因为Java是一种安全的语言和平台,所以内存不会被释放。 此外,关联的
PhantomReference
也不会在其ReferenceQueue
上排队。 虚拟机只会对对象调用一次finalize
。 JVM 规范中有一个很好的状态图。通常,如果您确实使用终结器,则应将声明保留为
@Override protected void Finalize() throws Throwable
,以免干扰 API。 更好的是使用受保护的终结器,如《Effective Java 第一版》中所示。当普林斯顿大学的一个小组使用它从不受信任的代码构建自定义
ClassLoader
时,这个特殊的技巧成为了头条新闻(无论如何,是圣何塞水星报的)。 尽管规范已经稍微收紧(Object
构造函数必须在调用终结器之前正常完成执行 - 在 J2SE 5.0 中指定,在 Java SE 6 中实现),但这仍然是一个问题领域。 如果您正在设计 API,请确保敏感类不能是子类,这样可以避免很多麻烦。Because Java is a safe language and platform, the memory is not freed. Also associated
PhantomReference
s will not be enqueued upon theirReferenceQueue
s. The VM will only ever callfinalize
on an object once. There's a nice state diagram in the JVM Spec.Typically if you do use a finaliser, you should leave the declaration as
@Override protected void finalize() throws Throwable
, so as not to disturb the API. Even better use a guarded finaliser, as in Effective Java 1st Ed.This particular trick hit the headlines (of the San Jose Mercury, anyway) when a group at Princeton used it to construct a custom
ClassLoader
from untrusted code. Although the spec has been slightly tightened (theObject
constructor has to finish executing normally before the finaliser can be called - specified in J2SE 5.0, implemented in Java SE 6), this still remains a problem area. If you are designing an API, make sure sensitive classes cannot be subclasses and save yourself much grief.