目录

一、Reference

1、SoftReference / WeakReference / PhantomReference

2、定义

3、ReferenceHandler

4、Cleaner

二、ReferenceQueue

1、定义

2、  enqueue / reallyPoll

3、poll / remove

4、forEach

三、Finalizer

1、定义

2、register

3、FinalizerThread

4、runFinalization / runAllFinalizers

5、InstanceKlass::register_finalizer


一、Reference

Reference是所有表示对象引用的类的抽象基类,定义了公共的方法,Reference所引用的对象称为referent。因为Reference的实现与JVM的垃圾回收机制是强相关的,所以不建议直接继承Reference,避免改变Reference的关键实现,其类继承关系如下图:

下面逐一讲解各类的使用和源码实现细节。

1、SoftReference / WeakReference / PhantomReference

这三个对象的表示引用是越来越弱的,SoftReference通常用来实现内存敏感的缓存,当内存不足的时候,为了获取可用内存空间会回收SoftReference所引用的对象,SoftReference本身会被放到创建时传入的ReferenceQueue中,JVM保证在抛出OutOfMemoryError异常前,清除所有的SoftReference。SoftReference增加了两个属性:

  • static long clock; //由垃圾回收器维护的表示时间的字段
  • long timestamp; //用来保存当前的clock

SoftReference改写了原来的构造方法和get方法的实现,增加了timestamp属性的更新逻辑,如下:

public SoftReference(T referent) {super(referent);this.timestamp = clock;
}public SoftReference(T referent, ReferenceQueue<? super T> q) {super(referent, q);this.timestamp = clock;}public T get() {T o = super.get();if (o != null && this.timestamp != clock)this.timestamp = clock;return o;}

WeakReference通常用来实现类似WeakMap的特殊Map,不能阻止key或者value被垃圾回收了,当垃圾回收器发现一个对象只是被WeakReference所引用就会回收掉该对象,并将关联的WeakReference加入到创建时传入的ReferenceQueue中。WeakReference没有新增属性,只是定义了自己的构造方法而已,如下:

public WeakReference(T referent) {super(referent);}public WeakReference(T referent, ReferenceQueue<? super T> q) {super(referent, q);}

PhantomReference通常用来实现一种更流畅的类似Object.finalize的清理功能,与SoftReference和WeakReference不同的是,PhantomReference的get方法永远返回null,为了保证其所引用的对象一直处于可被回收的状态,并且当垃圾回收器判断某个对象只是被PhantomReference所引用,然后将PhantomReference加入到创建时传入的ReferenceQueue中,这个时候垃圾回收器不会立即回收掉PhantomReference所引用的对象,而是等到所有的PhantomReference对象都放到ReferenceQueue中或者PhantomReference对象本身变得不可达。WeakReference也没有新增属性,改写了原有的get方法实现,永远返回null,如下:

public T get() {return null;}public PhantomReference(T referent, ReferenceQueue<? super T> q) {super(referent, q);}

这三个类的代码调用都大同小异,具体可以参考《java8 WeakHashMap接口实现源码解析》中WeakReference的应用。

2、定义

Reference包含的属性如下:

  • T referent; //所引用的对象
  • volatile ReferenceQueue<? super T> queue; //当所引用的对象referent被清理时用来保存Reference的队列,调用方可以通过ReferenceQueue的poll方法获取队列中的Reference实例,从而知道哪些referent对象被回收掉了
  • volatile Reference next; //ReferenceQueue使用,通过next属性将所有加入到ReferenceQueue中的Reference实例构成一个链表
  • transient Reference<T> discovered; //JVM使用的,用于将所有的Pending状态的Reference实例构成一个链表
  • static Lock lock = new Lock(); //用来修改Pending状态的Reference实例链表的锁
  • static Reference<Object> pending  = null; //Pending状态的Reference实例链表的链表头元素,垃圾回收器发现某个对象只有Reference实例引用,就会把Reference对象加入到这个链表中,而ReferenceHandler Thread不断从这个链表中移除元素,将其加入到Reference实例创建时传入的ReferenceQueue队列中

Reference定义了四种内部状态:

  • Active 新创建的Reference实例就是Active状态,当垃圾回收器发现所引用的对象referent的可达状态发生变更了,可能将Reference实例的状态改成Pending或者Inactive,取决于Reference实例创建时是否传入ReferenceQueue实例引用。如果是从Active改成Pending,则垃圾回收器还会将该Reference实例加入到pending属性对应的Reference列表中
  • Pending  pending属性对应的Reference列表中的Reference实例的状态都是Pending,等待ReferenceHandler Thread将这些实例加入到queue队列中
  • Enqueued queue属性对应的ReferenceQueue队列中的Reference实例的状态都是Enqueued,当实例从ReferenceQueue队列中移除就会变成Inactive。如果Reference实例在创建时没有传入ReferenceQueue,则永远不会处于Enqueued状态。
  • Inactive 变成Inactive以后,状态就不会再变更,等待垃圾回收器回收掉该实例

在不同的状态下,queue和next属性的赋值会发生变更,如下:

  • Active  queue就是Reference实例创建时传入的ReferenceQueue引用,如果没有传入或者传入的是null,则为ReferenceQueue.NULL;此时next属性为null。
  • Pending queue就是Reference实例创建时传入的ReferenceQueue引用,next属性是this
  • Enqueued  queue就是ReferenceQueue.ENQUEUED,next属性就是队列中的下一个元素,如果当前Reference实例就是最后一个,则是this
  • Inactive queue就是ReferenceQueue.NULL,next属性就是this

Reference定义的方法比较简单,如下:

其中get方法返回所引用的对象referent,clear方法用于将referent置为null,enqueue方法用于将当前Reference实例加入到创建时传入的queue队列中,isEnqueued方法判断当前Reference实例是否已加入queue队列中,tryHandlePending方法是ReferenceHandler Thread调用的用于处理Pending状态的Reference实例的核心方法,是包级访问的。重点关注ReferenceHandler的实现。

3、ReferenceHandler

ReferenceHandler继承自Thread,表示一个不断将Pending状态的Reference实例放入该实例创建时传入的ReferenceQueue实例中,所有处于Pending状态的Reference实例通过discovered实例属性构成链表,链表头就是Reference类的静态属性pending,在遍历链表时,如果链表为空则通过lock.wait()的方式等待;如果遍历的Reference实例是Cleaner,则调用其clean方法,用于清理资源清理。其实现如下:

private static class ReferenceHandler extends Thread {private static void ensureClassInitialized(Class<?> clazz) {try {Class.forName(clazz.getName(), true, clazz.getClassLoader());} catch (ClassNotFoundException e) {throw (Error) new NoClassDefFoundError(e.getMessage()).initCause(e);}}static {//预先加载并初始化两个类ensureClassInitialized(InterruptedException.class);ensureClassInitialized(Cleaner.class);}ReferenceHandler(ThreadGroup g, String name) {super(g, name);}public void run() {while (true) {//while true不断执行tryHandlePending(true);}}}static boolean tryHandlePending(boolean waitForNotify) {Reference<Object> r;Cleaner c;try {//注意lock和pending都是静态属性synchronized (lock) {if (pending != null) {//如果存在待处理的Reference实例r = pending;//Cleaner是PhantomReference的子类c = r instanceof Cleaner ? (Cleaner) r : null;//通过discovered属性将所有Pending的Reference实例构成一个链表//获取下一个处于Pending的Reference实例pending = r.discovered;//discovered属性置为空r.discovered = null;} else {//waitForNotify默认为true,阻塞当前线程直到其他线程唤醒if (waitForNotify) {lock.wait();}// retry if waitedreturn waitForNotify;}}} catch (OutOfMemoryError x) {//yield方法会让出当前线程的CPU处理时间,让垃圾回收线程获取更多的CPU时间,加速垃圾回收Thread.yield();return true;} catch (InterruptedException x) {// retryreturn true;}if (c != null) {//pending属性是Cleaner,执行清理c.clean();return true;}//pending属性不是Cleaner//Pending状态下,r.queue就是最初r创建时传入的ReferenceQueue引用ReferenceQueue<? super Object> q = r.queue;//将r加入到queue 队列中if (q != ReferenceQueue.NULL) q.enqueue(r);return true;}

ReferenceHandler的启动是通过静态static块完成的,如下:

static {ThreadGroup tg = Thread.currentThread().getThreadGroup();//往上遍历找到最初的父线程组for (ThreadGroup tgn = tg;tgn != null;tg = tgn, tgn = tg.getParent());//创建ReferenceHandler线程,并启动     Thread handler = new ReferenceHandler(tg, "Reference Handler");handler.setPriority(Thread.MAX_PRIORITY); //最高优先级handler.setDaemon(true); //后台线程handler.start();//允许访问SharedSecretsSharedSecrets.setJavaLangRefAccess(new JavaLangRefAccess() {@Overridepublic boolean tryHandlePendingReference() {return tryHandlePending(false);}});}

4、Cleaner

Cleaner继承自PhantomReference,其源码可以参考OpenJDK jdk\src\share\classes\sun\misc\Cleaner.java。Cleaner表示一种更轻量更健壮的资源清理方式,相对于Object的finalization机制,轻量是因为Cleaner不是JVM创建的,不需要借助JNI调用创建,执行资源清理的代码是ReferenceHandler Thread调用的而非finalizer Thread;健壮是因为Cleaner继承自PhantomReference,是最弱的一种引用类型,可以避免恶心的顺序问题。Cleaner封装了执行资源清理任务的逻辑,具体的资源清理逻辑通过创建Cleaner时的方法入参Runnable方法指定,Cleaner保证执行资源清理任务是线程安全的,即会捕获所有的异常,且保证只执行一次。一旦垃圾回收器发现Cleaner实例是phantom-reachable,即没有其他实例强引用该实例,垃圾回收器就会把Cleaner实例加入到Reference的pending队列中,由ReferenceHandler Thread负责调用其clean方法执行资源清理动作。Cleaner并不能完全替代Object的finalization机制,使用Cleaner时要求其资源清理逻辑比较简单,否则容易阻塞ReferenceHandler Thread,阻塞其他的资源清理任务执行。其实现如下:

public class Cleanerextends PhantomReference<Object>
{// 因为PhantomReference的构造方法要求必须传入ReferenceQueue参数,所以这里声明了一个,但是实际上并不会往里面添加Cleaner实例//因为ReferenceHandler Thread会直接调用Cleaner实例的clean方法,不会将其加入到dummyQueue队列中private static final ReferenceQueue<Object> dummyQueue = new ReferenceQueue<>();//Cleaner链表的链表头static private Cleaner first = null;private Cleanernext = null,prev = null;//add方法将cl加入到链表的头部private static synchronized Cleaner add(Cleaner cl) {if (first != null) {cl.next = first;first.prev = cl;}first = cl;return cl;}//remove方法将cl从链表中移除private static synchronized boolean remove(Cleaner cl) {//说明cl已经从链表移除了,不需要再处理if (cl.next == cl)return false;// Update listif (first == cl) {if (cl.next != null)first = cl.next;elsefirst = cl.prev;}if (cl.next != null)cl.next.prev = cl.prev;if (cl.prev != null)cl.prev.next = cl.next;//从链表移除后会将cl的prev和next都指向它自己cl.next = cl;cl.prev = cl;return true;}private final Runnable thunk;private Cleaner(Object referent, Runnable thunk) {super(referent, dummyQueue);this.thunk = thunk;}/*** 核心入口方法,创建Cleaner,thunk就是具体的执行资源清理的逻辑*/public static Cleaner create(Object ob, Runnable thunk) {if (thunk == null)return null;return add(new Cleaner(ob, thunk));}/*** Runs this cleaner, if it has not been run before.*/public void clean() {//首先从队列移除当前Cleaner实例if (!remove(this))return;try {//执行资源清理thunk.run();} catch (final Throwable x) {//捕获所有异常,打印err日志并退出AccessController.doPrivileged(new PrivilegedAction<Void>() {public Void run() {if (System.err != null)new Error("Cleaner terminated abnormally", x).printStackTrace();System.exit(1);return null;}});}}}

Cleaner通过prev,next属性内部维护了一个双向链表,其中静态属性first就是链表头,即所有的Cleaner实例通过链表维护着引用关系,但是这种引用是phantom-reachable的,一旦某个Cleaner实例没有强引用则会被垃圾回收器加入到Reference的pending队列中,等待被处理。Cleaner的核心方法有两个,一是创建Cleaner实例的create方法,该方法会将创建的实例加入到链表中;另外一个是执行资源清理的clean方法,该方法将当前实例从链表中移除,然后执行Cleaner实例创建时传入的thunk,如果出现异常则打印err日志并导致JVM进程终止。

可以参考java.nio.DirectByteBuffer类中Cleaner的应用,如下:

cleaner是该类的一个私有属性,在构造函数中初始化,当DirectByteBuffer实例被垃圾回收器回收掉了,这个cleaner属性对应的Cleaner实例就没有其他强引用了,只剩下Cleaner内部维护的链表对其的虚引用了,就会被垃圾回收器加入到Reference的pending队列中,等待被处理。

二、ReferenceQueue

1、定义

ReferenceQueue主要用来通知Reference实例的使用方Reference实例对应的referent对象已经被回收掉了,允许使用方对Reference实例本身做适当的处理。注意ReferenceQueue本身并不直接持有Reference实例的引用,如果Reference实例本身变得不可达了,则无论Reference实例对应的referent对象被回收掉了,Reference实例都不会被添加到ReferenceQueue中。

ReferenceQueue包含的属性如下:

  • static ReferenceQueue<Object> NULL = new Null<>();  //如果Reference实例的queue等于NULL,则表示该实例已经从队列中移除
  • static ReferenceQueue<Object> ENQUEUED = new Null<>(); // //如果Reference实例的queue等于ENQUEUED,则表示该实例已经加入到队列中
  • Lock lock = new Lock(); //改写队列的锁
  • volatile Reference<? extends T> head = null;  //Reference链表的头部
  • long queueLength = 0; //表示Reference链表的长度

上面的Null 和Lock都是ReferenceQueue的内部类,如下:

private static class Null<S> extends ReferenceQueue<S> {boolean enqueue(Reference<? extends S> r) {return false;}}static private class Lock { };

ReferenceQueue跟正常的队列实现不同,ReferenceQueue依赖于Reference的next属性构成一个链表,链表头就是ReferenceQueue的静态head属性,加入到队列中实际就是插入到链表的头部。当Reference实例加入到ReferenceQueue中,Reference实例变成新的链表头,next属性就指向原来的链表头,queue属性变成ENQUEUED,相关逻辑在enqueue方法中;当Reference实例从ReferenceQueue中移除时,next属性被重置为自己,原来的next属性变成新的链表头,queue属性变成NULL,相关逻辑在reallyPoll方法中。重点关注以下方法的实现。

2、  enqueue / reallyPoll

enqueue方法将Reference实例加入到链表的头部,reallyPoll方法移除并返回链表的头部,这两方法都要求获取lock属性的锁,其中enqueue是public方法,reallyPoll方法是private方法。具体实现如下:

//enqueue方法将某个Reference实例加入到队列中boolean enqueue(Reference<? extends T> r) { /* Called only by Reference class */synchronized (lock) {// Check that since getting the lock this reference hasn't already been// enqueued (and even then removed)ReferenceQueue<?> queue = r.queue;if ((queue == NULL) || (queue == ENQUEUED)) {return false;}assert queue == this;//将r插入到链表的头部,r的queue置为ENQUEUED,表示其已经加入到队列中,r的next属性置为它自己r.queue = ENQUEUED;//插入第一个元素时,head等于null,此时r的next属性就是r,插入以后的元素时,next属性就是headr.next = (head == null) ? r : head;head = r;queueLength++;if (r instanceof FinalReference) {//增加FinalReference的计数sun.misc.VM.addFinalRefCount(1);}//唤醒其他的等待线程lock.notifyAll();return true;}}private Reference<? extends T> reallyPoll() {       /* Must hold lock */Reference<? extends T> r = head;if (r != null) {@SuppressWarnings("unchecked")Reference<? extends T> rn = r.next;//将链表头从链表中移除,移除的Reference实例的queue会被置为NULL,next置为它自己head = (rn == r) ? null : rn;r.queue = NULL;r.next = r;queueLength--;if (r instanceof FinalReference) {//FinalReference的计数器减1sun.misc.VM.addFinalRefCount(-1);}return r;}return null;}

3、poll / remove

这两方法都是移除并返回链表的头元素,区别在于poll方法不会阻塞,立即返回null,remove方法会阻塞当前线程,直到当前线程获取了一个Reference实例或者累计等待时间超过了指定时间,remove方法还有一个没有参数的重载版本,会阻塞当前线程,直到当前线程被唤醒,等待时间无限制,如果被唤醒了链表头还是null则返回null,即只等待一次。其实现如下:

 /***  从当前队列中移除并返回链表头元素,如果为空则返回null,WeakHashMap中就是调用此方法遍历队列中所有的Reference实例*/public Reference<? extends T> poll() {if (head == null)//队列为空,返回nullreturn null;synchronized (lock) {//获取队列的锁,移除并返回链表头元素return reallyPoll();}}/*** 移除并返回队列的头元素,最多等待timeout,如果timeout等于0,则只等待一次直到线程被唤醒,等待时间无限制*/public Reference<? extends T> remove(long timeout)throws IllegalArgumentException, InterruptedException{if (timeout < 0) {throw new IllegalArgumentException("Negative timeout value");}synchronized (lock) {Reference<? extends T> r = reallyPoll();if (r != null) return r;long start = (timeout == 0) ? 0 : System.nanoTime();//相当于while死循环for (;;) {//等待最多timeout,如果timeout为0,则等待其他线程调用notify或者notifyAlllock.wait(timeout);//移除并返回链表头部元素r = reallyPoll();if (r != null) return r;if (timeout != 0) {//检查是否等待超时long end = System.nanoTime();//如果timeout为0,则start为0,timeout算出来的就是一个负值,会立即返回null,即只wait一次//如果timeout不为0,则可能wait多次,直到多次wait的累计时间大于设定的值,返回nulltimeout -= (end - start) / 1000_000;if (timeout <= 0) return null;//继续下一次waitstart = end;}}}}/*** remove(long timeout)的重载版本,timeout固定传0*/public Reference<? extends T> remove() throws InterruptedException {return remove(0);}

4、forEach

forEach方法用于遍历链表中的所有的Reference实例,通常用于调试目的,要求调用方不能保持对Reference实例的引用,避免影响其正常销毁,其实现如下:

/**用来遍历队列中所有Reference实例,通常用于调试目的,要求调用方不能保持对Reference实例的引用,避免影响其正常销毁*/void forEach(Consumer<? super Reference<? extends T>> action) {//注意执行forEach时不要求获取锁,所以读取的元素可能已经从队列中移除了for (Reference<? extends T> r = head; r != null;) {action.accept(r);@SuppressWarnings("unchecked")Reference<? extends T> rn = r.next;if (rn == r) {if (r.queue == ENQUEUED) {//说明已经遍历到队列最后一个元素,将r置为nullr = null;} else {//r.queue等于NULL,说明r已经从队列中移除了,需要从head开始重新遍历,以后r后面多个元素都可能被移除了,而且//此时也无法获取下一个遍历元素的引用r = head;}} else {// next in chainr = rn;}}}

三、Finalizer

1、定义

Finalizer继承自FinalReference,FinalReference是一种特殊的引用类型,主要用来辅助实现Object finalization机制,其定义如下:

Finalizer定义的属性如下:

  • static ReferenceQueue<Object> queue = new ReferenceQueue<>(); //全局的ReferenceQueue队列
  • static Finalizer unfinalized = null; //所有Finalizer 实例构成的链表的头元素
  • static final Object lock = new Object(); //修改链表的锁
  • private Finalizer next = null, prev = null; //用来构成链表的表示下一个和上一个元素

Finalizer是借助垃圾回收器对Reference实例的特殊处理机制实现的,每创建一个实现了finalize方法的对象时,JVM会通过调用Finalizer的register方法创建一个新的Finalizer实例,该对象就是Finalizer实例的referent对象,所有的Finalizer实例构成一个链表。当某个对象只被Finalizer实例所引用,则将对应的Finalizer实例加入到Reference维护的pending链表中,通过ReferenceHandler Thread将pending链表中的Finalizer实例加入到Finalizer定义的全局ReferenceQueue中。Finalizer自身会另外起一个新线程,FinalizerThread,不断的从全局的ReferenceQueue中取出带出来的Finalizer实例,然后将该实例从Finalizer链表中移除,最后调用对应对象的finalize方法执行资源的清理,并将对referent对象的引用置为null,保证该对象能够会回收掉。当JVM进程即将退出,JVM会通过java.lang.Runtime另起线程处理掉全局ReferenceQueue中未处理完的Finalizer实例,通过java.lang.Shutdown另起线程处理掉Finalizer链表中的Finalizer实例,即没有加入到Reference维护的pending链表中的Finalizer实例。重点关注以下方法的实现。

2、register

register是JVM创建对象时,如果该类实现了finalize方法,则以新创建的对象作为参数调用此方法创建一个Finalizer实例,并将其加入到Finalizer链表的头部,其实现如下:

 /*在对象创建的时候由JVM调用 */
static void register(Object finalizee) {new Finalizer(finalizee);}private Finalizer(Object finalizee) {super(finalizee, queue);//执行构造方法的时候,会将当前实例加入到链表中add();}private void add() {synchronized (lock) {//获取锁,将this插入到链表的头部if (unfinalized != null) {this.next = unfinalized;unfinalized.prev = this;}unfinalized = this;}}

3、FinalizerThread

FinalizerThread就是一个不断循环的线程任务,从queue属性中获取待处理的Finalizer实例,将该实例从Finalizer链表中移除然后调用其finalize方法,最后将Finalizer实例对referent对象的引用置为null,从而保证GC能够正确回收该对象,其实现如下:

private static class FinalizerThread extends Thread {//标记运行状态private volatile boolean running;FinalizerThread(ThreadGroup g) {super(g, "Finalizer");}public void run() {//已运行if (running)return;//isBooted返回false表示JVM未初始化完成while (!VM.isBooted()) {try {//等待JVM初始化完成VM.awaitBooted();} catch (InterruptedException x) {// ignore and continue}}final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();running = true;for (;;) {try {//移除并返回链表头元素,如果为空则等待Finalizer f = (Finalizer)queue.remove();//执行Finalizer任务f.runFinalizer(jla);} catch (InterruptedException x) {// ignore and continue}}}}private void runFinalizer(JavaLangAccess jla) {synchronized (this) {//hasBeenFinalized返回true,说明该元素已经从队列移除了,直接返回if (hasBeenFinalized()) return;//将当前实例从队列中移除remove();}try {//获取所引用的对象referentObject finalizee = this.get();if (finalizee != null && !(finalizee instanceof java.lang.Enum)) {//实际调用Object的finalize方法jla.invokeFinalize(finalizee);/* 去掉对finalizee的引用,让GC回收掉该实例 */finalizee = null;}} catch (Throwable x) { }//将所引用的对象referent置为null,即去掉对referent的引用,让GC回收掉该实例super.clear();}private boolean hasBeenFinalized() {//next等于this说明该实例已经从链表中移除了,已经执行过Finalized方法了return (next == this);}private void remove() {synchronized (lock) {//获取锁,将this从链表中移除if (unfinalized == this) {if (this.next != null) {unfinalized = this.next;} else {unfinalized = this.prev;}}if (this.next != null) {this.next.prev = this.prev;}if (this.prev != null) {this.prev.next = this.next;}//将next和prev都指向自己,表示已经从链表中移除this.next = this;   /* Indicates that this has been finalized */this.prev = this;}}

FinalizerThread是通过静态static块启动的,如下:

static {ThreadGroup tg = Thread.currentThread().getThreadGroup();for (ThreadGroup tgn = tg;tgn != null;tg = tgn, tgn = tg.getParent());Thread finalizer = new FinalizerThread(tg);finalizer.setPriority(Thread.MAX_PRIORITY - 2);finalizer.setDaemon(true);finalizer.start();}

上述jla.invokeFinalize(finalizee)方法的实现如下:

可以搜索SharedSecrets.setJavaLangAccess方法的调用链找到上述实现,如下:

4、runFinalization / runAllFinalizers

runFinalization由Runtime.runFinalization()方法调用,负责清理掉queue中未处理的Finalizer实例;runAllFinalizers由java.lang.Shutdown,负责清理掉Finalizer链表中剩余的即未加入到queue中的Finalizer实例;两者都是调用forkSecondaryFinalizer方法执行清理任务,该方法会在系统线程组下另起一个线程执行指定任务,并等待该线程执行完成,如果执行异常,则终止当前线程。其实现如下:

 /* Called by Runtime.runFinalization(),执行queue中未处理的Finalizer */static void runFinalization() {if (!VM.isBooted()) {return;}forkSecondaryFinalizer(new Runnable() {private volatile boolean running;public void run() {// in case of recursive call to run()if (running)return;final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();running = true;for (;;) {//不断遍历queue中所有的Finalizer,然后执行finalize方法Finalizer f = (Finalizer)queue.poll();if (f == null) break;f.runFinalizer(jla);}}});}/* Invoked by java.lang.Shutdown,执行未加入到queue中的Finalizer */static void runAllFinalizers() {if (!VM.isBooted()) {return;}forkSecondaryFinalizer(new Runnable() {private volatile boolean running;public void run() {// in case of recursive call to run()if (running)return;final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();running = true;for (;;) {//不断遍历unfinalized链表中的元素,执行finalize方法Finalizer f;synchronized (lock) {f = unfinalized;if (f == null) break;unfinalized = f.next;}f.runFinalizer(jla);}}});}/* 在系统线程组下创建一个新的线程执行指定任务,并等待任务执行完成,之所以开启一个新的线程,是为了与已经死锁了或者停顿的finalizer thread隔离开来加速finalize方法的执行*/private static void forkSecondaryFinalizer(final Runnable proc) {AccessController.doPrivileged(new PrivilegedAction<Void>() {public Void run() {ThreadGroup tg = Thread.currentThread().getThreadGroup();//从当前线程的线程组往上遍历找到最初的系统线程组for (ThreadGroup tgn = tg;tgn != null;tg = tgn, tgn = tg.getParent());//启动一个新线程执行proc任务    Thread sft = new Thread(tg, proc, "Secondary finalizer");sft.start();try {//等待proc任务执行完成sft.join();} catch (InterruptedException x) {//执行异常,中断当前线程Thread.currentThread().interrupt();}return null;}});}

5、InstanceKlass::register_finalizer

该方法就是JVM中调用Finalizer的register方法的具体实现了,如下:

instanceOop InstanceKlass::register_finalizer(instanceOop i, TRAPS) {if (TraceFinalizerRegistration) {//打印跟踪日志tty->print("Registered ");i->print_value_on(tty);tty->print_cr(" (" INTPTR_FORMAT ") as finalizable", (address)i);}//i是新创建的对象instanceHandle h_i(THREAD, i);//result表示调用结果JavaValue result(T_VOID);//args表示方法参数JavaCallArguments args(h_i);//获取调用方法methodHandle mh (THREAD, Universe::finalizer_register_method());//执行方法调用JavaCalls::call(&result, mh, &args, CHECK_NULL);return h_i();
}static Method*      finalizer_register_method()     { return _finalizer_register_cache->get_method(); }

_finalizer_register_cache的初始化在Universe的universe_post_init方法中,如下:

详细代码说明可以参考《Hotspot 内存管理之Universe 源码解析》 。

register_finalizer方法的调用链如下:

InstanceKlass::allocate_instance就是根据Class创建对象的底层实现,可以参考《Hotspot Java对象创建和TLAB源码解析》;另外几个Runtime结尾的是给字节码的汇编指令或者编译器的编译代码使用的方法,最终的调用场景一样是创建对象。

Hotspot 对象引用Reference和Finalizer 源码解析相关推荐

  1. Hotspot 垃圾回收之GenCollectedHeap 源码解析

    目录 1.定义 2.构造方法 / initialize / post_initialize 3.do_collection 4.do_full_collection 5.collect 6.VM_Ge ...

  2. Hotspot 垃圾回收之VM_Operation 源码解析

    目录 一.VM_Operation ​二.VMThread 1.定义 2.create / destroy 3.run / wait_for_vm_thread_exit 4.loop 5.VMThr ...

  3. Hotspot 垃圾回收之oop_iterate(二) 源码解析

    目录 1.java.lang.Class 1.1.Class实例中oop_size.klass等属性是哪来的? 1.2._offset_of_static_fields 1.3 为什么从_offset ...

  4. Hotspot 垃圾回收之ReferenceProcessor(二) 源码解析

    目录 1.process_discovered_reflist 2.process_phaseJNI 3.process_discovered_references 4.preclean_discov ...

  5. Hotspot 重量级锁ObjectMonitor(一) 源码解析

    目录 1.定义 2.TrySpin_VaryDuration 3.ObjectWaiter 4.EnterI 5.JavaThreadBlockedOnMonitorEnterState / OSTh ...

  6. Hotspot 重量级锁ObjectMonitor(二) 源码解析

    目录 1.AddWaiter / DequeueWaiter /DequeueSpecificWaiter 2.wait 3.notify 4.notifyAll 5.exit 6.try_enter ...

  7. Handler全家桶之 —— Handler 源码解析

    本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 本文首发于本人简书 前言 好记性不如烂笔头. 这是一个系列文章,将会包括: Handler全家桶之 -- Handler 源码解析 ...

  8. python整型数据源码分析_Python2 基本数据结构源码解析

    Python2 基本数据结构源码解析 Contents 0x00. Preface 0x01. PyObject 0x01. PyIntObject 0x02. PyFloatObject 0x04. ...

  9. Redis源码解析——字典基本操作

    有了<Redis源码解析--字典结构>的基础,我们便可以对dict的实现进行展开分析.(转载请指明出于breaksoftware的csdn博客) 创建字典 一般字典创建时,都是没有数据的, ...

最新文章

  1. pyqt设置按钮可用
  2. 云原生一体化数仓发布
  3. 从部署 httpd 入手,理清 k8s 配置中的 containerPort、port、nodePort、targetPort
  4. ZooKeeper系列(三)
  5. python multiprocessing.Process 应用
  6. linux关闭自动更新,Ubuntu开启系统自动升级与取消自动更新的方法,
  7. MySQL数据常用命令
  8. Spring Boot/Spring面试常见问题
  9. 理解委托的两类必要方法
  10. 利用vsftpd在Linux构建安全的FTP服务
  11. vuforia for unity 注意事项
  12. Memtest移植到海思上面测试DDR
  13. 合并两个有序数组 Go语言
  14. win10设置透明任务栏
  15. iPad及BT4下的WEP破解实验与分析 | Network Security
  16. 如果光猫+hadoop,有化学反应吗?
  17. Lemon LemonLime 中 SPJ Special Judge 使用 实践 入门 a
  18. MySQL utf8mb4字符集按中文拼音排序
  19. 在窗口程序中打开控制台
  20. 线性回归的理解与公式推导

热门文章

  1. CSS布局之——左边、上边固定,内容自适应(Vue)
  2. Matlab:数据分析与多项式计算
  3. C#情怀与未来,怨天尤人还是抓住机会,能否跟上dnc新时代浪潮?
  4. random.seed(0)
  5. 图文解读 Infor10 ERP SyteLine的功能
  6. [windows优化]win10折腾过程
  7. 安卓常用6种设计模式总结
  8. BZOJ1022: [SHOI2008]小约翰的游戏John
  9. jaccard相似度算法
  10. iOS 微信支付和支付宝支付