简体   繁体   English

为什么finalize()只被垃圾收集器调用一次?

[英]Why is finalize() only called once by garbage collector?

Quotes from SCJP 6 study guide: SCJP 6学习指南引用:

In the finalize() method you could write code that passes a reference to the object in question back to another object, effectively uneligiblizing the object for garbage collection. finalize()方法中,您可以编写将对相关对象的引用传递回另一个对象的代码,从而有效地使对象无法进行垃圾回收。 If at some point later on this same object becomes eligible for garbage collection again, the garbage collector can still process this object and delete it. 如果稍后在同一个对象上再次符合垃圾回收条件,垃圾收集器仍然可以处理该对象并将其删除。 The garbage collector, however, will remember that, for this object, finalize() already ran, and it will not run finalize() again 但是,垃圾收集器会记住,对于这个对象, finalize()已经运行,并且它不会再次运行finalize()

Why is it designed so? 它为什么这么设计? The purpose of the finalize() method still holds good even when the object is marked of collection second time. 即使第二次将对象标记为集合时, finalize()方法的目的仍然很好。 Then why Java decides to skip call to finalize() ? 那么为什么Java决定跳过调用finalize()

I don't know if its the original reason, but the current implementation enqueues Finalizer instances (internal subclass of Reference ) for objects overriding the finalize method with an internal ReferenceQueue that gets polled by a dedicated FinalizerThread . 我不知道它是否是最初的原因,但是当前的实现将Finalizer实例( Reference内部子类)排列为覆盖finalize方法的对象,其内部ReferenceQueue由专用的FinalizerThread进行轮询。

And because the JVM has no way of knowing whether the object would need to be finalized a second time it cannot decide whether it would have to enqueue a new Finalizer once the finalize() method has been called. 并且因为JVM无法知道对象是否需要第二次完成,所以无法确定在调用finalize()方法后是否必须将新的Finalizer排入队列。

Anyway, you should avoid using finalize() . 无论如何,你应该避免使用finalize() It makes object allocation more costly, prevents escape analysis and is not a very reliable way of managing native resources because the GC can postpone the finalization for an unbounded amount of time. 它使对象分配成本更高,防止转义分析,并且不是一种非常可靠的管理本机资源的方法,因为GC可以推迟无限时间的最终化。

Objects with an enabled finalizer are ineligible for collection; 具有启用的终结器的对象不符合收集条件; the GC only examines them after determining all the other objects which are ineligible for collection, however, and makes note of all the objects which would have been eligible for collection but for the existence of the enabled finalizer , and runs the finalize methods of such objects as soon as practical. 然而,在确定了所有其他不符合收集条件的对象之后,GC才会检查它们,并记录所有可能有资格收集的对象但是是否存在已启用的终结器 ,并运行此类对象的finalize方法一实际。 Finalizable objects won't become eligible for collection until the finalizer has run, but the GC will have no way of distinguishing objects which become eligible for finalization as soon as the finalizer finishes, or those which were rendered ineligible for finalization as a result of actions by some object's finalizer and became eligible for collection at some later time. 在终结器运行之前,可终结对象将不具备收集资格,但GC无法在终结器完成后立即区分有资格完成的对象,或者由于操作而无法完成最终确定的对象通过某个对象的终结器,稍后有资格收集。

The .NET Framework includes methods called IIRC GC.SuppressFinalize and GC.ReRegisterForFinalization which make it possible for code which knows an object's finalizer won't do anything useful to tell the GC not to bother calling it, and allows for code which knows a finalizer ran "too soon" to request that it run again later. .NET Framework包含名为IIRC GC.SuppressFinalizeGC.ReRegisterForFinalization方法,这使得知道对象的终结器的代码不会做任何有用的事情来告诉GC不要打扰它,并允许知道终结器的代码“太快”,要求它稍后再次运行。 The JVM, however, does not include such a feature. 但是,JVM不包含此类功能。 Since having all finalizable objects automatically reregistered for finalization once the finalizer runs would prevent them from ever getting collected, and since there's no way to manually reregister them, the net consequence is that there's no usable pattern via which an object's finalizer can be run more than once. 由于在终结器运行后自动重新注册所有可终结对象以进行最终化,因此无法收集它们,并且由于无法手动重新注册它们,因此最终结果是没有可用的模式,通过该模式可以运行对象的终结器一旦。

On the other hand, it is possible to achieve a similar effect by defining a nested class object which is finalizable, having the outer class object hold a reference to a nested-class instance, and having that nested class instance's "finalize" method chain back to cleanup code in its owner. 另一方面,可以通过定义一个可终结的嵌套类对象来实现类似的效果,使外部类对象保持对嵌套类实例的引用,并使该嵌套类实例的“finalize”方法链返回清理其所有者的代码。 If that cleanup code discards the nested-class instance and replaces it with a new one, then that new instance will trigger its finalizer (chaining back to its owner) on the next GC cycle where the owner is found to be unreferenced. 如果该清理代码丢弃嵌套类实例并将其替换为新实例,则该新实例将在下一个GC周期触发其终结器(链接回其所有者),其中发现所有者未被引用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM