有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

引用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. 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

为什么设计成这样?即使对象第二次被标记为collection,finalize()方法的目的仍然有效。那么为什么Java决定跳过对finalize()的调用呢


共 (2) 个答案

  1. # 1 楼答案

    我不知道这是否是最初的原因,但当前的实现为覆盖finalize方法的对象排队Finalizer实例(内部子类^{}),对象使用内部^{}由专用的FinalizerThread轮询

    而且,由于JVM无法知道对象是否需要第二次完成,因此它无法决定在调用finalize()方法后是否必须将新的Finalizer排队

    无论如何,您应该避免使用finalize()。它使对象分配成本更高,阻止了转义分析,并且不是一种非常可靠的管理本机资源的方法,因为GC可以无限期地推迟完成

  2. # 2 楼答案

    已启用终结器的对象不符合收集条件;但是,GC仅在确定所有其他不符合收集条件的对象后才对其进行检查,并记录所有如果没有启用的终结器,本应符合收集条件的对象,并尽快运行此类对象的finalize方法。在终结器运行之前,可终结对象将不符合收集条件,但GC将无法在终结器完成后立即区分符合终结条件的对象,或者,由于某个对象的终结器的操作而使其不符合终结条件,并在以后某个时间符合收集条件的对象

    这个。NET框架包括名为IIRCGC.SuppressFinalizeGC.ReRegisterForFinalization的方法,这使得知道对象的终结器不会做任何有用的事情来告诉GC不要费心调用它的代码成为可能,并且允许知道终结器“太快”运行的代码请求它稍后再次运行。然而,JVM不包含这样的特性。由于一旦终结器运行,所有可终结对象都会自动重新注册以进行终结,这将阻止它们被收集,并且由于无法手动重新注册它们,因此最终的结果是,没有可用的模式可以让对象的终结器多次运行

    另一方面,通过定义一个可终结的嵌套类对象,使外部类对象持有对嵌套类实例的引用,并使该嵌套类实例的“finalize”方法链回到其所有者中的清理代码,也可以实现类似的效果。如果清除代码丢弃嵌套类实例并用新实例替换它,那么新实例将在发现所有者未被引用的下一个GC循环中触发其终结器(链接回其所有者)