当前位置: 首页 > 面试题库 >

如何在Java中将一个对象标记为finalize(这样就不会再次调用finalize方法)?

薛承志
2023-03-14
问题内容

主要问题在主题中,但是让我展示一下我对Java终结处理的看法,以便我可以再问您一点。

gc通过标记所有活动对象开始垃圾收集。当所有可到达的对象都标记为“活动”时。所有其他对象均不可访问。下一步是检查每个无法到达的对象,并确定是否可以立即将其清除或应首先完成。
如果对象的finalize方法具有主体,则gc会考虑采用另一种方法,然后将此对象终结并应终结。
如果对象的finalize方法的主体为空(受保护的void finalize(){}),则该对象不可终结,可以立即被gc清除。
(我对吗?)
所有可终结对象都将放在同一队列中,以便以后一一终结。据我了解,可终结对象可能会花费大量时间放置在队列中,而等待轮回完成。之所以会发生这种情况,是因为通常只有一个名为Finalizer的线程正在从队列中获取对象并调用其finalize方法,并且当我们在某些对象的finalize方法中进行一些耗时的操作时,队列中的其他对象将等待很长时间才能被完成。好了,当对象完成后,将其标记为“已完成”并从队列中删除。

在下一个垃圾回收过程中,收集器将再次看到此对象不可访问,并且再次具有非空的finalize方法,因此应将该对象放入队列(再次)-但这不是因为收集器以某种方式看到该对象被标记为已完成。

(这是我的主要问题:以何种方式将此对象标记为“已定稿”,收集器如何知道该对象不应再次完成?)


问题答案:

只要我们谈论的是HotSpot JVM …

对象本身未标记为已完成。

每次创建新的finalize对象时,JVM都会创建一个额外的对象FinalizerRef(与Weak / Soft / Phantom引用有点类似)。

一旦使用强引用证明您的对象不可访问,便会处理对该对象的特殊引用。您的对象的FinalizerRef将被添加到终结器队列(链接列表,与其他引用类型相同)。

当终结器线程从队列中使用FinalizerRef时,它将使指向对象的null指针为空(尽管线程将保持对对象的强引用,直到终结器完成)。

一旦FinalizerRef无效,对象将无法再进入终结器队列。

BTW

您可以使用以下命令在GC日志中查看首选项处理时间(和引用数)-XX:+PrintReferenceGC(请参阅更多GC诊断JVM选项)



 类似资料:
  • 我们最近将消息处理应用程序从Java7升级到Java8。自升级以来,我们偶尔会发现一个异常,即在读取流时,流已被关闭。日志记录显示终结器线程正在对保存流的对象调用(这反过来会关闭流)。 守则的基本大纲如下: 和是自制的MIME/HTTP库的一部分。扩展,它具有以下特性: 异常发生在的调用链中,如下所示: 写入部件的标题,然后调用 调用我们的实用工具方法将内容流式传输到输出 只返回传入contstr

  • 问题内容: 我需要知道何时在中调用该方法。我创建了一个测试类,该法通过覆盖该方法来在调用该方法时将其写入文件。它不执行。谁能告诉我它为什么不执行的原因? 问题答案: 通常,最好不要依赖进行任何清理等工作。 根据Javadoc(值得阅读),它是: 当垃圾回收确定不再有对该对象的引用时,由垃圾回收器在对象上调用。 正如Joachim指出的那样,如果对象始终是可访问的,则在程序生命中可能永远不会发生这种

  • 如果重写finalize()并引用一个对象会发生什么。那个对象会被垃圾回收吗?从内存中清除该对象的另一种方法是什么?

  • 问题内容: (此问题不同于您为什么要实现finalize()?此问题与从Java平台弃用有关,另一个问题与在应用程序中是否应使用此机制有关。) 为什么在Java 9中不推荐使用该方法? 是的,它可能以错误的方式使用(例如,从垃圾收集中保存对象(虽然仅一次)或尝试关闭其中的某些本机资源(总比不完全关闭要好))以及许多其他方法可能会被错误地使用。 那么,是真的如此危险或绝对没有用,有必要将其逐出Jav

  • 本文向大家介绍Java禁止使用finalize方法,包括了Java禁止使用finalize方法的使用技巧和注意事项,需要的朋友参考一下 什么是finalize方法 finalize()方法被定义在Java.lang.Object类中,意味着所有的类都可以重载这个方法。java垃圾回收器只之道释放那些经由new分配的内存,所以如果你的对象并非通过new获得的内存,那么垃圾回收器就不知道如何释放该对象