Reference生命周期
当Reference引用的对象不可达时,Reference对象自身会被放入一个pending队列。同时有一个引用处理线程会不断从队列里面拉取Reference对象进行处理。
Reference成员变量
// Reference所引用的对象
private T referent; /* Treated specially by GC */
// 保存Reference对象的队列,如果有注册队列则回收引用会加入该队列
volatile ReferenceQueue<? super T> queue;
//上面引用队列referenceQueue中保存引用的链表
/* When active: NULL
* pending: this
* Enqueued: next reference in queue (or this if last)
* Inactive: this
*/
@SuppressWarnings("rawtypes")
Reference next;
/* When active: next element in a discovered reference list maintained by GC (or this if last) 由gc管理的引用发现链表的下一个引用
* pending: next element in the pending list (or null if last)
* otherwise: NULL
*/
transient private Reference<T> discovered; /* used by VM */
//等待入队列的引用链表,gc往该链表加引用对象,Reference-handler线程消费该链表,它通过discovered连接它的元素
/* List of References waiting to be enqueued. The collector adds
* References to this list, while the Reference-handler thread removes
* them. This list is protected by the above lock object. The
* list uses the discovered field to link its elements.
*/
private static Reference<Object> pending = null;
//最高优先级的守护线程
private static class ReferenceHandler
Reference有4中状态
/* A Reference instance is in one of four possible internal states:
*
* Active: Subject to special treatment by the garbage collector. Some
* time after the collector detects that the reachability of the
* referent has changed to the appropriate state, it changes the
* instance's state to either Pending or Inactive, depending upon
* whether or not the instance was registered with a queue when it was
* created. In the former case it also adds the instance to the
* pending-Reference list. Newly-created instances are Active.
*
* Pending: An element of the pending-Reference list, waiting to be
* enqueued by the Reference-handler thread. Unregistered instances
* are never in this state.
*
* Enqueued: An element of the queue with which the instance was
* registered when it was created. When an instance is removed from
* its ReferenceQueue, it is made Inactive. Unregistered instances are
* never in this state.
*
* Inactive: Nothing more to do. Once an instance becomes Inactive its
* state will never change again.
*
* The state is encoded in the queue and next fields as follows:
*
* Active: queue = ReferenceQueue with which instance is registered, or
* ReferenceQueue.NULL if it was not registered with a queue; next =
* null.
*
* Pending: queue = ReferenceQueue with which instance is registered;
* next = this
*
* Enqueued: queue = ReferenceQueue.ENQUEUED; next = Following instance
* in queue, or this if at end of list.
*
* Inactive: queue = ReferenceQueue.NULL; next = this.
*
active: 活动状态,对象存在强引用状态,还没有被回收
pending: 垃圾回收器将没有强引用的Reference对象放入到pending队列中,等待ReferenceHander线程处理(前提是这个Reference对象创建的时候传入了ReferenceQueue,否则的话对象会直接进入Inactive状态)
Enqueued:ReferenceHander线程将pending队列中的对象取出来放到ReferenceQueue队列里;
Inactive:处于此状态的Reference对象可以被回收,并且其内部封装的对象也可以被回收掉了
状态之间的转换如图
Reference对象的状态主要由queue和next这两个成员决定
active: queue = ReferenceQueue, next = null;
pending: queue = ReferenceQueue, next = this;
enqueued: queue = ReferenceQueue.ENQUEUED
inactive: queue = ReferenceQueue.NULL, next = this.
ReferenceQueue
ReferenceQueue是一个链表,链表里的元素是加入进去的Reference实例,使用的是链表的头插法,所以是一个先进后出的队列。
ReferenceQueue是使用wati()和notifyAll()实现生产者和消费者
ReferenceQueue源码解析
public ReferenceQueue() { }
//内部类,用于标识队列状态
private static class Null<S> extends ReferenceQueue<S> {
boolean enqueue(Reference<? extends S> r) {
return false;
}
}
//标识该引用已被当前队列移除过,当Reference对象创建时没有指定queue或Reference对象已经处于inactive状态
static ReferenceQueue<Object> NULL = new Null<>();
//标识该引用已加入当前队列, 当Reference已经被ReferenceHander线程从pending队列移到queue里面时
static ReferenceQueue<Object> ENQUEUED = new Null<>();
// 入队操作
boolean enqueue(Reference<? extends T> r) { /* Called only by Reference class */
synchronized (lock) {
// 已经移除过,或者已经入队的直接返回
ReferenceQueue<?> queue = r.queue;
if ((queue == NULL) || (queue == ENQUEUED)) {
return false;
}
//只有r的队列是当前队列才允许入队
assert queue == this;
queue设置为ENQUEUED状态,标识Reference已经入队
r.queue = ENQUEUED;
// 头插法,插入队列
r.next = (head == null) ? r : head;
head = r;
//队列长度加1
queueLength++;
if (r instanceof FinalReference) {
sun.misc.VM.addFinalRefCount(1);
}
//通知消费者可以消费了
lock.notifyAll();
return true;
}
}
// 出队操作,将头部第一个对象移出队列并返回,如果队列为空,则等待timeout时间后,返回null,这个方法会阻塞线程
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();
for (;;) {
// 队列为空,则等待对象入队
lock.wait(timeout);
r = reallyPoll();
if (r != null) return r;
if (timeout != 0) {
long end = System.nanoTime();
timeout -= (end - start) / 1000_000;
if (timeout <= 0) return null;
start = end;
}
}
}
}
// 将头部第一个对象移出队列并返回
private Reference<? extends T> reallyPoll() { /* Must hold lock */
Reference<? extends T> r = head;
if (r != null) {
head = (r.next == r) ? null :r.next;
r.queue = NULL;
r.next = r;
queueLength--;
if (r instanceof FinalReference) {
sun.misc.VM.addFinalRefCount(-1);
}
return r;
}
return null;
}
ReferenceHandler
ReferenceHandler线程是一个拥有最高优先级的守护线程。它的任务就是当pending队列不为空的时候,循环将pending队列里面的头部的Reference移除出来,如果这个对象是个Cleaner实例,那么就直接执行它的clean方法来执行清理工作;否则放入到它自己的ReferenceQueue里面
/* High-priority thread to enqueue pending References
*/
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 {
// pre-load and initialize InterruptedException and Cleaner classes
// so that we don't get into trouble later in the run loop if there's
// memory shortage while loading/initializing them lazily.
ensureClassInitialized(InterruptedException.class);
ensureClassInitialized(Cleaner.class);
}
ReferenceHandler(ThreadGroup g, String name) {
super(g, name);
}
public void run() {
while (true) {
//循环处理pending队列
tryHandlePending(true);
}
}
}
static boolean tryHandlePending(boolean waitForNotify) {
Reference<Object> r;
Cleaner c;
try {
synchronized (lock) {
//若队列不为空,则取队列的第一个对象
if (pending != null) {
r = pending;
c = r instanceof Cleaner ? (Cleaner) r : null;
// 指向队列的下一个节点,这样队头就出列了
pending = r.discovered;
r.discovered = null;
} else {
// 队列为空,则等待唤醒
if (waitForNotify) {
lock.wait();
}
// retry if waited
return waitForNotify;
}
}
} catch (OutOfMemoryError x) {
return true;
} catch (InterruptedException x) {
// retry
return true;
}
// 如果是Cleaner对象,则执行其clean方法
if (c != null) {
c.clean();
return true;
}
// 将引用对象放入ReferenceQueue
ReferenceQueue<? super Object> q = r.queue;
if (q != ReferenceQueue.NULL) q.enqueue(r);
return true;
}
在 tryHandlePending()方法里面,检查 pending是否为null,如果pending不为null,则将pending进行enqueue,否则线程进入 wait状态。简单来说,垃圾回收器会把 References添加进入,ReferenceHandler会移除它,即discovered和pending是由垃圾回收器进行赋值的。
总结
Reference具有4中状态,当Reference与ReferenceQueue一起使用时,若对象被回收,那么Reference就会被放入到ReferenceQueue中。这个过程由最高优先级的ReferenceHandler线程来处理。