FinalReference类的功能、jvm中finalize()方法的实现方式、为什么实现finalize()方法的类要至少经过两次gc才能回收。
FinalReference 的子类是Finalizer,FinalReference 类的权限是default的,Finalizer 类的权限是default的,并且有final修饰符,这两个类原则上不让开发者使用。他们和jvm配合实现java中对象实例被gc回收之前执行finalize方法。java中的类有构造方法,不像C++中有析构函数,finalize某种意义上是“析构函数”。
接下来看一下java是怎么实现finalize方法的。
首先需要解释一个概念,finalizee 类,finalize在超类Object中的原型是
protected void finalize() throws Throwable { }
如果子类复写了这个方法,既这个方法体不为空,这种类成为finalizee类,生成的实例时finalizee实例。这种实例jvm会和其他普通对象的实例多几个不同的处理步骤。
从FinalReference类中的结构来看。当一个finalizee对象被创建时,jvm会以当前对象为参数调用static void register(Object finalizee)方法。该方法封装成Finalizer实例并放置到ufinalized链表上。unfinalized是静态成员属性,在jvm实例中是唯一的。
final class Finalizer extends FinalReference {
private static ReferenceQueue queue = new ReferenceQueue();
private static Finalizer unfinalized = null; // finalizee对象对应的Finalizer链表,jvm中全局的
private static final Object lock = new Object();
private Finalizer next = null,prev = null;
private void add()
private void remove()
private Finalizer(Object finalizee) {
super(finalizee, queue);
add();
}
static void register(Object finalizee) {
new Finalizer(finalizee);
}
private void runFinalizer(JavaLangAccess jla)
private static void forkSecondaryFinalizer(final Runnable proc)
static void runFinalization()
static void runAllFinalizers()
}
另一方面,在静态代码块中会有一个优先级较低的守护线程,该守护线程从queue中取出Finalizer,调用runFinalizer,runFinalizer运行该finalizee对象的finalize方法。runFinalizer中限制只会运行一次finalize方法。同时把当前finalizee对应的Finalizer从unfinalized链表中移除。是什么时候向queue中放置的Finalizer呢?gc判定当前的finalizee对象需要回收的时候,会把finalizee对应的Finalizer放到queue中,但此时该finalizee还未被回收。这些逻辑是Reference类中的逻辑(可以参看文章中“引用的内部逻辑”部分)。

当运行完finalizee对象的finalize方法后,对应的Finalizer从unfinalized链表中移除、Finalizer中的referent置为null,finalizee对象变成孤立的对象。如果再次发生gc,finalizee对象会被回收,Finalizer会被回收。因此一个finalizee对象会至少经过两次的gc才能被真正回收。
本文深入探讨Java中Finalize机制的工作原理,包括FinalReference和Finalizer类的作用,以及实现finalize()方法的类如何至少经过两次GC才能被回收。解析了finalizee类的概念,以及JVM如何通过Finalizer类和守护线程来执行对象的finalize方法。
1062

被折叠的 条评论
为什么被折叠?



