如何在Java中标记为最终化的对象(以便第二次不调用finalize方法)?

主要问题是在主题中,但让我展示我对Java中的最终化过程的看法,以便我可以再问你一点。

那么gc通过标记所有活动对象来启动垃圾收集。 当所有可到达的对象都标记为“活动”时。 所有其他对象都无法访问。 下一步是检查每个无法到达的对象,并确定它是否可以立即进行清理,或者应该首先完成。 如果对象的finalize方法有一个主体,那么gc会想到下一个方法,那么这个对象是可以最终确定的,应该最终确定; 如果对象的finalize方法有一个空体(protected void finalize(){})那么它不能最终化并且现在可以被gc清理。 (我是对的吗?)
所有可终结的对象将被放入同一队列中,以便稍后逐一完成。 据我所知,可终结的对象可以花费大量时间放在队列中,同时等待轮到它完成。 这可能发生,因为通常只有一个名为Finalizer的线程从队列中获取对象并调用它们的finalize方法,当我们在某个对象的finalize方法中有一些耗时的操作时,队列中的其他对象将等待很长时间才能完成。 好的,当一个对象完成后,它被标记为FINALIZED并从队列中删除。 在下一个垃圾收集过程中,收集器将看到此对象无法访问(再次)并且具有非空的finalize方法(再次),因此该对象应该被放入队列中(再次) – 但它不会因为收集器以某种方式看到这个对象被标记为FINALIZED。 (这是我的主要问题:这个对象被标记为FINALIZED的方式,收集器如何知道该对象不应该再次定型?)

只要我们谈论HotSpot JVM ……

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

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

一旦您的对象被certificate无法通过强引用访问,就会处理对此对象的特殊引用。 对象的FinalizerRef将被添加到终结器队列(链接列表,与其他引用类型相同)。

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

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

BTW

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

JVM将元数据存储在对象头中。 调用具有子类finalize()的任何对象,即使是空的。 放入队列不需要很长时间,但它可以在队列中等待很长时间。

我不知道真正的,实现的最终化过程是如何工作的,但如果我必须这样做,我会这样做 – 在对象元数据中存储一个三态标志,告诉GC是否对象刚刚停止存在在使用中,需要运行终结器,或者可以将其移除。 您可能需要检查java源代码以获取详细信息,但这应该是整体模式:

(新)

 object.metadata.is_finalized=NEEDS_FINALIZE; 

(在gc中)

 while ((object=findUnreachableObject())!=null) { if (object.metadata.is_finalized==NEEDS_FINALIZE) { if (hasNonNullBody(object.finalize)) { Finalizer.addForProcessing(object); object.metadata.is_finalized=IN_FINALIZER_QUEUE; } else { object.metadata.is_finalized=REMOVE_NOW; } } if (object.metadata.is_finalized==REMOVE_NOW) { // destroy the object and free the memory } } 

(在Finalizer中)

 while ((object=getObjectForProcessing)!=null) { object.finalize(); object.metadata.is_finalized=REMOVE_NOW; }