当前位置: 首页 > 知识库问答 >
问题:

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

长孙硕
2023-03-14

引用SCJP 6学习指南:

finaliz()方法中,您可以编写代码,将对所讨论对象的引用传递给另一个对象,从而有效地取消垃圾回收机制对该对象的资格。如果在同一对象稍后的某个时候再次有资格使用垃圾回收机制,垃圾回收器仍然可以处理并删除该对象。然而,垃圾回收器将记住,对于该对象,finaliz()已经运行,并且不会再次运行finaliz()

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

共有2个答案

阎德业
2023-03-14

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

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

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

寿子默
2023-03-14

我不知道这是否是最初的原因,但当前的实现将终结器实例(引用的内部子类)排入队列,以便对象使用内部引用队列覆盖finalize方法,该队列由专用的终结器线程轮询。

而且,由于JVM无法知道对象是否需要第二次完成,因此它无法决定一旦调用了finaliz()方法,是否需要对一个新的Finalizer进行排队。

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

 类似资料:
  • 问题内容: 阅读完这个问题之后,我想起了什么时候教我Java的,并且告诉我永远不要调用finalize()或运行垃圾回收器,因为“这是一个大黑盒子,您无需担心”。有人可以将其理由简化为几句话吗?我敢肯定,我可以阅读Sun的有关此事的技术报告,但是我认为一个不错的,简短的简单答案将满足我的好奇心。 问题答案: 简短的答案:Java垃圾回收是一个非常精细的工具。System.gc()是大锤。 Java

  • 问题内容: 是什么决定了垃圾收集器何时真正收集?它是在一定时间之后还是在一定数量的内存用完之后发生的吗?还是还有其他因素? 问题答案: 它在确定是时候运行时运行。在世代垃圾收集器中,一种常见的策略是在第0代内存分配失败时运行收集器。也就是说,每次你分配一小块内存(大块通常直接放置在“旧”代中)时,系统都会检查gen-0堆中是否有足够的可用空间,如果没有,则运行GC释放空间以使分配成功。然后将旧数据

  • 我从C代码中调用Java方法。每次调用时,我调用AttachCurrentThread,调用后,我调用DetachCurrentThread。 这可以很好地工作,但问题是,我看到了由此导致的ECSESSIVE垃圾收集,即几乎每个通过JNI的调用。VisualVM图形上的小集合基本上都是绿色的!从本机代码到Java的调用速率是每秒数百次。在调用过程中,我还可以看到创建了过多的Java线程,如Thre

  • 问题内容: 我是Java新手,对Java中的垃圾收集器感到困惑。它实际上是做什么的,什么时候生效。请描述Java中垃圾收集器的一些属性。 问题答案: 该垃圾收集器是运行在一个程序的Java虚拟机,其摆脱其未使用的Java应用程序了对象。它是自动内存管理的一种形式。 当典型的Java应用程序运行时,它正在创建新的对象,例如和,但是在一段时间之后,这些对象将不再使用。例如,看下面的代码: 在上面的代码

  • 我遇到了一个JNI程序随机内存不足的问题。 这是一个32位java程序,它读取文件,进行一些图像处理,通常使用250MB到1GB。然后丢弃所有这些对象,然后程序对通常需要100-250MB的JNI程序进行一系列调用。 当交互运行时,我从未见过问题。但是,当对许多文件连续运行批处理操作时,JNI程序将随机运行内存溢出。它可能对一个或两个文件有内存问题,然后对下一个10个文件运行正常,然后再次出现故障

  • Java 15 使 ZGC、Z 垃圾收集器成为标准功能。它是 Java 15 之前的一个实验性功能。它是低延迟、高度可扩展的垃圾收集器。 ZGC 是在 Java 11 中作为一项实验性功能引入的,因为开发人员社区认为它太大而无法提前发布。 即使在机器学习应用程序等海量数据应用程序的情况下,ZGC 也具有高性能和高效工作。它确保在处理数据时不会因垃圾收集而长时间停顿。它支持 Linux、Window