目录
- Reference 状态
1.1 Active
1.2 Pending
1.3 Enqueued
1.4 Inactive - reference-hannel 线程
2.1 启动线程
2.2 线程执行
1.Reference 状态
每个Reference状态列表是Active、Pending、Enqueued、Inactive (本文也将基于以下这四种状态做出源码解读)
状态间主要的标识:
用Reference的成员变量queue与next(类似于单链表中的next)来标识
ReferenceQueue<? super T> queue;
Reference next; //当状态不为active,gc自动赋值为this
有了这些约束,GC 只需要检测next字段就可以知道是否需要对该引用对象(reference)采取特殊处理
- 如果next为null,那么说明该引用为Active状态
- 如果next不为null,那么 GC 应该按其正常逻辑处理该引用。
什么特殊处理?
GC在状态active发送变化时,会主动把 weakReference中的 reference置null,PhantomReference 中的 reference 无视 (PhantomReference的get方法重写返回null,可能就因为这原因就没有置null了),并给next赋值this,以及pending等。(别问我为啥,测出来的。。。。培训出来就这水平了)
1.1 Active
描述:
active 状态下的reference会受到GC的特别对待,GC在发现对象的可达性变成合适的状态后将变更reference状态,具体是变更为pending还是Inactive,取决于是否注册了 queue
特点:
//如果构造参数中没指定queue,那么queue为ReferenceQueue.NULL
//否则为构造参数中传递过来的queue
queue = ReferenceQueue || ReferenceQueue.NULL
next = null
源码分析:
Reference(T referent) {
this(referent, null);
}
Reference(T referent, ReferenceQueue<? super T> queue) {
this.referent = referent;
this.queue = (queue == null) ? ReferenceQueue.NULL : queue;
}
1.2 Pending
描述:
pending-Reference列表中的引用都是这个状态。
它们等着被内部线程ReferenceHandler处理(调用ReferenceQueue.enqueue方法)
没有注册的实例不会进入这个状态!
特点:
//ReferenceQueue 是注册的队列,从构造参数哪里传过来的
queue=ReferenceQueue
next = this
源码分析:
- 想进Pending就必须要注册队列,ReferenceQueue.NULL 是不会enqueue
static boolean tryHandlePending(boolean waitForNotify) {
//some code
ReferenceQueue<? super Object> q = r.queue;
if (q != ReferenceQueue.NULL) q.enqueue(r);
return true;
}
- next=this,这个应该是GC赋的值,只要reference的state一改变,这个next就莫名其妙被赋值了。
3.似乎明白了 ReferenceQueue.ENQUEUED 的含义
public boolean isEnqueued() {
return (this.queue == ReferenceQueue.ENQUEUED);
}
1.3 Enqueued
描述:
调用ReferenceQueue.enqueued方法后的引用处于这个状态中。
没有注册的实例不会进入这个状态。
特点:
queue = ReferenceQueue.ENQUEUED;
next = queue的下一个引用, 如果已经queue是最后一个元素,那么就是自身.
源码分析:
可以看出 整体是一种先进后出的栈结构。head作为栈头。r.next指向成员变量 head,如果head为null,那么就指向自己(为了后面的压栈好找元素)
private volatile Reference<? extends T> head = null;
boolean enqueue(Reference<? extends T> r) {
//some code
r.queue = ENQUEUED;
r.next = (head == null) ? r : head;
head = r;
//some code
}
1.4 Inactive
描述:
最终状态,处于这个状态的引用对象,状态不会在改变。
两种途径到这个状态:
1.referenceQueue 调用 reallyPoll ,
2.不注册 referenceQueue,reference state变化时。
特点:
queue = ReferenceQueue.NULL;
next = this
源码分析:
private Reference<? extends T> reallyPoll() { /* Must hold lock */
Reference<? extends T> r = head;
//some code
r.queue = NULL;
r.next = r;
//some code
}
2.reference-hannel 线程
2.1启动线程
- 说明jvm一启动线程就跟着启动了
- 提供了一个 JavaLangRefAccess 来提供外接接口访问
static {
ThreadGroup tg = Thread.currentThread().getThreadGroup();
for (ThreadGroup tgn = tg;
tgn != null;
tg = tgn, tgn = tg.getParent());
Thread handler = new ReferenceHandler(tg, "Reference Handler");
/* If there were a special system-only priority greater than
* MAX_PRIORITY, it would be used here
*/
handler.setPriority(Thread.MAX_PRIORITY);
handler.setDaemon(true);
handler.start();
// provide access in SharedSecrets
SharedSecrets.setJavaLangRefAccess(new JavaLangRefAccess() {//提供一个访问接口
@Override
public boolean tryHandlePendingReference() {
return tryHandlePending(false);
}
});
}
2.2 线程执行
- pending == null 时,会阻塞线程,所以不会一直调用。gc肯定notify了
- Cleaner 是个重要的接口,非常适合做资源回收。
- 如果注册了引用队列,会将引用enqueue进去。
static boolean tryHandlePending(boolean waitForNotify) {
Reference<Object> r;
Cleaner c;
try {
synchronized (lock) {
if (pending != null) {
r = pending;
// 'instanceof' might throw OutOfMemoryError sometimes
// so do this before un-linking 'r' from the 'pending' chain...
c = r instanceof Cleaner ? (Cleaner) r : null;
// unlink 'r' from 'pending' chain
pending = r.discovered;
r.discovered = null;
} else {
// The waiting on the lock may cause an OutOfMemoryError
// because it may try to allocate exception objects.
if (waitForNotify) {
lock.wait();
}
// retry if waited
return waitForNotify;
}
}
} catch (OutOfMemoryError x) {
// Give other threads CPU time so they hopefully drop some live references
// and GC reclaims some space.
// Also prevent CPU intensive spinning in case 'r instanceof Cleaner' above
// persistently throws OOME for some time...
Thread.yield();
// retry
return true;
} catch (InterruptedException x) {
// retry
return true;
}
// Fast path for cleaners
if (c != null) {
c.clean();
return true;
}
ReferenceQueue<? super Object> q = r.queue;
if (q != ReferenceQueue.NULL) q.enqueue(r);
return true;
}
网友评论