一、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);
}
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 waited
return waitForNotify;
}
}
} catch (OutOfMemoryError x) {
//yield方法会让出当前线程的CPU处理时间,让垃圾回收线程获取更多的CPU时间,加速垃圾回收
Thread.yield();
return true;
} catch (InterruptedException x) {
// retry
return 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();
//允许访问SharedSecrets
SharedSecrets.setJavaLangRefAccess(new JavaLangRefAccess() {
@Override
public 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 Cleaner
extends 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 Cleaner
next = 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 list
if (first == cl) {
if (cl.next != null)
first = cl.next;
else
first = 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属性就是head
r.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的计数器减1
sun.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)
//队列为空,返回null
return 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或者notifyAll
lock.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的累计时间大于设定的值,返回null
timeout -= (end - start) / 1000_000;
if (timeout <= 0) return null;
//继续下一次wait
start = 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置为null
r = null;
} else {
//r.queue等于NULL,说明r已经从队列中移除了,需要从head开始重新遍历,以后r后面多个元素都可能被移除了,而且
//此时也无法获取下一个遍历元素的引用
r = head;
}
} else {
// next in chain
r = 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 {
//获取所引用的对象referent
Object 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方法中,如下:

详细代码说明可以参考Universe 。
register_finalizer方法的调用链如下:

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