主要问题在于主题,但是让我展示我对Java中最终化过程的看法,以便我可以向您提出更多要求。
gc通过标记所有活动对象来启动垃圾收集。当所有可到达的对象都标记为“实时”时。所有其他对象都无法访问。下一步是检查每个无法到达的对象,并确定它是否可以立即进行清理,或者应该首先完成。 如果对象的finalize方法有一个主体,那么gc会想到下一个方法,那么这个对象可以最终化并且应该最终确定;如果对象的finalize方法有一个空体(protected void finalize(){})那么它就不能最终化了,现在可以被gc清理。 (我对吗?) /> 所有可终结的对象将被放入同一队列中,以便稍后逐一完成。据我所知,可终结的对象可以花费大量时间放在队列中,同时等待轮到他们完成。这可能发生,因为通常只有一个名为Finalizer的线程从队列中获取对象并调用它们的finalize方法,当我们在某个对象的finalize方法中有一些耗时的操作时,队列中的其他对象将等待很长时间才能完成。好的,当一个对象完成后,它被标记为FINALIZED并从队列中删除。 在下一个垃圾收集过程中,收集器将看到此对象无法访问(再次)并且具有非空的finalize方法(再次),因此该对象应该被放入队列中(再次) - 但它赢了因为收集器以某种方式看到这个对象被标记为FINALIZED。 (这是我的主要问题:这个对象被标记为FINALIZED的方式,收集器如何知道此对象不应该再次敲定?)
答案 0 :(得分:5)
只要我们谈论HotSpot JVM ......
对象本身未标记为已完成。
每次创建新的finalize对象时,JVM都会创建一个额外的对象FinalizerRef(与Weak / Soft / Phantom引用有些相似)。
一旦证明您的对象无法通过强引用访问,则会处理对此对象的特殊引用。对象的FinalizerRef将被添加到终结器队列(链接列表,与其他引用类型相同)。
当终结器线程从队列中消耗FinalizerRef时,它会将其null指针置为null(尽管线程将保持对对象的强引用,直到终结器完成)。
一旦FinalizerRef无效,对象就无法再进入终结队列。
顺便说一句
您可以使用-XX:+PrintReferenceGC
(see more GC diagnostic JVM options)
答案 1 :(得分:1)
JVM将元数据存储在对象标头中。调用具有子类finalize()的任何对象,即使为空。放入队列不需要很长时间,但它可以在队列中等待很长时间。
答案 2 :(得分:1)
我不知道真正的,实现的最终化过程是如何工作的,但如果我必须这样做,我会这样做 - 在对象元数据中存储一个三态标志,告诉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;
}