ReferenceQueue<T>
用来收集被 GC 后的对象(这个对象在这里是 会被 SoftReference、WeakReference、PhantomReference 包装的),这样的话,用户就可以在这个对象 GC 之后,做一些其它后续操作,比如 反向操作、数据清理等
下面是源码解读:
public class ReferenceQueue<T> {
//构造方法 ,使用的时候,一般需要用户自己 new,自己保持这个 对象
public ReferenceQueue() { }
//内部类 Null,这个 Null 重写了 enqueue 方法,就是不会把 GC 回收后的 引用对象(用户真实值是这个类的一个referent属性,此时这个属性已经被GC回收了) 存放到 这个 GC回收通知引用队列里面
private static class Null<S> extends ReferenceQueue<S> {
boolean enqueue(Reference<? extends S> r) {
return false;
}
}
//java 提供的 NULL 的 GC回收通知引用队列,(不会放入 GC回收通知引用队列)
static ReferenceQueue<Object> NULL = new Null<>();
//java 提供的 ENQUEUED 的 GC回收通知引用队列,(不会放入 GC回收通知引用队列)
static ReferenceQueue<Object> ENQUEUED = new Null<>();
//内部 锁 class
static private class Lock { };
//内部 锁 对象
private Lock lock = new Lock();
//存放GC回收后的 Reference 引用对象的 队列 的 head,需要和 Reference 对象的 next 属性配合使用
private volatile Reference<? extends T> head = null;
//队列长度
private long queueLength = 0;
//加入到 GC引用回收队列(此时用户的真正数据类已经被回收了);这个方法只会被 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)) {//如果是这2个java 内部回收队列,则返回 false
return false;
}
assert queue == this;
r.queue = ENQUEUED; //已经进入GC回收队列的话,这个queue就被置为 ENQUEUED(已入队模式)
r.next = (head == null) ? r : head;
head = r; //添加到队列头部
queueLength++; //队列长度+1
if (r instanceof FinalReference) { //这个就是 finalize 方法 的用处
sun.misc.VM.addFinalRefCount(1);
}
lock.notifyAll(); //激活其它等待锁
return true; //返回true,表示 加入到了 GC引用回收队列
}
}
//返回 引用队列 的 head
private Reference<? extends T> reallyPoll() { /* Must hold lock */
Reference<? extends T> r = head;
if (r != null) {
head = (r.next == r) ?
null :
r.next; // Unchecked due to the next field having a raw type in Reference
r.queue = NULL;
r.next = r;
queueLength--; //队列长度 -1
if (r instanceof FinalReference) {
sun.misc.VM.addFinalRefCount(-1);
}
return r;
}
return null;
}
//返回 引用队列 的 head;如果 GC回收通知引用队列 是null则快速返回null
public Reference<? extends T> poll() {
if (head == null)
return null;
synchronized (lock) {
return reallyPoll(); //加锁使用 reallyPoll 获取
}
}
//从 GC回收通知引用队列中 移除元素,没有元素 则会阻塞,(超时没有元素,则会返回null);用户在后处理 GC元素的时候使用
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(); //使用reallyPoll获取 队列head元素
if (r != null) return r; //非空则直接返回
long start = (timeout == 0) ? 0 : System.nanoTime();
for (;;) {
lock.wait(timeout); //null 则会等待
r = reallyPoll(); //仔次获取
if (r != null) return r;
if (timeout != 0) { //如果设置了超时时间的话,超时没有元素,则会返回null
long end = System.nanoTime();
timeout -= (end - start) / 1000_000;
if (timeout <= 0) return null;
start = end;
}
}
}
}
//从 GC回收通知引用队列中 移除元素,没有元素 则会阻塞;用户在后处理 GC元素的时候使用
public Reference<? extends T> remove() throws InterruptedException {
return remove(0);
}
}
Reference 软、弱、虚 引用 的 父类
这个类及其子类 内部会存在一个 真正 存放 用户 真实值的属性 referent,当然 GC 回收的时候,也是回收的这个
真实值;
再配合不同的 ReferenceQueue 引用队列,就可以实现不同 GC 回收策略和回收后处理 策略。
public abstract class Reference<T> {
private T referent; //真实的用户的值,Reference及其子类 都是 包装了这个真实的值,可以被GC清理;不同的子类GC清理的策略不同
volatile ReferenceQueue<? super T> queue; //GC回收通知引用队列
Reference next; //链表结果; 存放 GC回收通知引用队列 数据
//整个jvm中唯一,与discovered结合使用,pending 与 discovered构成了一个链表;这个链表就是pending-Reference链表
//Garbage Collector 回收了referent对象后,会把相应的Reference对象放入pending-Reference链表中
//pending-Reference链表: pending -> pending.discovered -> pending.discovered.discovered -> pending.discovered.discovered.discovered
//Reference-handler线程 把 pending 入队到 ReferenceQueue,入队后 r = pending; pending = r.discovered; r.discovered = null;
//进入pending-Reference链表,Reference对象需要满足两个条件
// 1. Reference所引用的对象已经不存在其它强引用;
// 2. Reference对象在创建的时候,指定了ReferenceQueue;
private static Reference<Object> pending = null;
transient private Reference<T> discovered;
static private class Lock { } //内部锁class
private static Lock lock = new Lock(); //内部锁实例
//获取用户真实值方法,被GC清理后,就是 null 了
public T get() {
return this.referent;
}
//手动清理用户真实值方法
public void clear() {
this.referent = null;
}
//这个对象(里面的用户真实值)是否已经 进去到 GC回收通知引用队列了 (即是否已经被GC了)
public boolean isEnqueued() {
return (this.queue == ReferenceQueue.ENQUEUED);
}
//手动 把这个对象 加入到 GC回收通知引用队列
public boolean enqueue() {
return this.queue.enqueue(this);
}
//构造方法,不使用 GC回收通知引用队列
Reference(T referent) {
this(referent, null);
}
构造方法,使用 GC回收通知引用队列
Reference(T referent, ReferenceQueue<? super T> queue) {
this.referent = referent;
this.queue = (queue == null) ? ReferenceQueue.NULL : queue;
}
//把 penging 的 对象 放入到对应的 GC回收通知吟咏队列里面去
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); //入GC回收通知引用队列
return true;
}
//内部 ReferenceHandler 类;Reference-handler线程
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) { //不停调用tryHandlePending,用于将pending-Reference链表的元素加入到ReferenceQueue
tryHandlePending(true);
}
}
}
//类初始化 静态代码块
static { //全局只会有一个 Reference-handler线程
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(); //启动 Reference-handler线程
// provide access in SharedSecrets
SharedSecrets.setJavaLangRefAccess(new JavaLangRefAccess() {
@Override
public boolean tryHandlePendingReference() {
return tryHandlePending(false);
}
});
}
}
强引用
只有没有任何饮用的时候,才可能被回收
SoftReference 软引用
只有当 jvm 内存不足的时候,才会回收这些只有软引用对象
public class SoftReference<T> extends Reference<T> {
static private long clock; //GC 垃圾回收才能更新它
private long timestamp; //get 方法会更新它
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 弱引用
只要 垃圾回收线程扫描它所在的区域,一旦发现 这个对象只有软引用时,就会回收
public class WeakReference<T> extends Reference<T> {
public WeakReference(T referent) {
super(referent);
}
public WeakReference(T referent, ReferenceQueue<? super T> q) {
super(referent, q);
}
}
可以看到 WeakReference 就是 继承了 Reference,其它的没有做任何改变。
PhantomReference 虚引用
必须配合一个 ReferenceQueue 引用队列才能工作;一个对象如果只存在虚引用的话。那么任何时候都可能被回收
这种引用类型更关注的是 被垃圾回收器回收的活动。被回收时会收到⼀个系统通知。
public class PhantomReference<T> extends Reference<T> {
public PhantomReference(T referent, ReferenceQueue<? super T> q) {
super(referent, q);
}
public T get() {
return null;
}
}
可以看到 必须要传入一个 GC回收通知引用队列;并且获取 用户真实值一直是null
FinalReference 用来实现 finalization
class FinalReference<T> extends Reference<T> {
public FinalReference(T referent, ReferenceQueue<? super T> q) {
super(referent, q);
}
}
Finalizer
final class Finalizer extends FinalReference<Object> {
private static ReferenceQueue<Object> queue = new ReferenceQueue<>(); //GC回收通知引用队列
private static Finalizer unfinalized = null; //没有被 finalizer 的 双向队列 header
private Finalizer next = null, prev = null; //没有被 finalizer 的 双向队列,向前、向后 值
private static final Object lock = new Object(); //内部锁对象
//增加元素到 unfinalized 双向队列里面
private void add() {
synchronized (lock) {
if (unfinalized != null) {
this.next = unfinalized;
unfinalized.prev = this;
}
unfinalized = this;
}
}
//构造方法是 private的,外部不能实例化
private Finalizer(Object finalizee) {
super(finalizee, queue);
add();
}
//JVM 在类加载的时候,如果发现一个类重写了 finalize 方法的化,将会把这个类 注册到 unfinalized队列里面
static void register(Object finalizee) {
new Finalizer(finalizee);
}
//从 unfinalized 双向链表中移除第一个元素
private void remove() {
synchronized (lock) {
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;
}
this.next = this; /* Indicates that this has been finalized */
this.prev = this;
}
}
//是否已经被remove了
private boolean hasBeenFinalized() {
return (next == this);
}
//执行 用户 类 的 finalize 方法
private void runFinalizer(JavaLangAccess jla) {
synchronized (this) {
if (hasBeenFinalized()) return; //已经被remove了,那就什么也不做
remove(); //从 unfinalized 双向链表中移除第一个元素
}
try {
Object finalizee = this.get(); //获取 实际用户对象
if (finalizee != null && !(finalizee instanceof java.lang.Enum)) {
jla.invokeFinalize(finalizee); //执行 实际用户对象 的 finalize 方法
/* Clear stack slot containing this variable, to decrease
the chances of false retention with a conservative GC */
finalizee = null;
}
} catch (Throwable x) { } //忽略异常
super.clear(); //实际用户对象 置null
}
//内部 FinalizerThread 类
private static class FinalizerThread extends Thread {
private volatile boolean running; //running 标志
//构造方法
FinalizerThread(ThreadGroup g) {
super(g, "Finalizer");
}
//线程方法
public void run() {
if (running)
return;
// Finalizer thread starts before System.initializeSystemClass
// is called. Wait until JavaLangAccess is available
while (!VM.isBooted()) {
// delay until VM completes initialization
try {
VM.awaitBooted();
} catch (InterruptedException x) {
// ignore and continue
}
}
final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
running = true;
for (;;) {
try {
Finalizer f = (Finalizer)queue.remove(); //从 GC回收通知引用队列 不断获取 finalizer reference 元素
f.runFinalizer(jla); //执行 finalizer reference 元素 的 runFinalizer 方法
} catch (InterruptedException x) {
// ignore and continue
}
}
}
}
//类静态代码块
static {
ThreadGroup tg = Thread.currentThread().getThreadGroup();
for (ThreadGroup tgn = tg;
tgn != null;
tg = tgn, tgn = tg.getParent()); //找到 根 线程组
Thread finalizer = new FinalizerThread(tg); //启动 finalizerThread 线程
finalizer.setPriority(Thread.MAX_PRIORITY - 2);
finalizer.setDaemon(true);
finalizer.start();
}
//执行一个 runnable 对象的 方法
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());
Thread sft = new Thread(tg, proc, "Secondary finalizer");
sft.start();
try {
sft.join();
} catch (InterruptedException x) {
/* Ignore */
}
return null;
}});
}
/* Called by Runtime.runFinalization() */
//通过 Runtime.runFinalization() 调用
static void runFinalization() {
if (!VM.isBooted()) {
return;
}
forkSecondaryFinalizer(new Runnable() {
private volatile boolean running;
public void run() {
if (running)
return;
final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
running = true;
for (;;) {
Finalizer f = (Finalizer)queue.poll();
if (f == null) break;
f.runFinalizer(jla);
}
}
});
}
/* Invoked by java.lang.Shutdown */
//通过 java.lang.Shutdown 调用
static void runAllFinalizers() {
if (!VM.isBooted()) {
return;
}
forkSecondaryFinalizer(new Runnable() {
private volatile boolean running;
public void run() {
if (running)
return;
final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
running = true;
for (;;) {
Finalizer f;
synchronized (lock) {
f = unfinalized;
if (f == null) break;
unfinalized = f.next;
}
f.runFinalizer(jla);
}}});
}
}
参考
https://blog.csdn.net/qq_43579103/article/details/108840706
https://blog.csdn.net/ctwy291314/article/details/85095750