别睡!打起精神来学习!
📖什么是Reference
Reference本身是一个抽象类,它的实现类有SoftReference
,WeakReference
,PhantomReference
,FinalReference
。GC回收器会与该类中的变量做直接交互。
当垃圾收集器检测到referent
对象可达性为不可达时,Reference的实例状态将从Active
变更为Pending
,当实例被ReferenceHandler
放入ReferenceQueue
中时,它的状态从Pending
转换为Enqueued
,当ReferenceQueue
消费完成后,则变换为最终状态Inactive
,此时实例会被释放掉。
Reference用于管理对象自身的四种状态:
- Active 新创建的Reference的实例状态
- Pending 实例即将被
ReferenceHandler
线程加入ReferenceQueue
队列的状态 - Enqueued 实例在
ReferenceQueue
队列中,处于消费中或等待中的状态 - Inactive 最终状态
♾️垃圾回收器
🚩可达性分析算法
JVM判断一个对象是否存活时,默认使用了可达性分析算法
。通过GC Root
对象向下搜索,搜索到的对象都是可达对象,而剩余对象全都是不可达对象。如下图,红色为不可达对象,蓝色为可达对象。
我们可以看到只有在GC Root这条链上并被这条引用链引用的对象才可以被认定为可达对象。
GC Root对象有哪些呢?
- 本地方法栈JNI引用的对象,也就是Native引用的对象
- 虚拟机栈中引用的对象,也就是栈帧中的本地变量(说白了就是执行方法中new的对象)
- 方法区里常量引用的对象
- 方法区中静态属性引用的对象
🌲Reference源码解读
首先来看一下Reference
的核心成员变量
private T referent;
volatile ReferenceQueue<? super T> queue;
volatile Reference next;
transient private Reference<T> discovered;
private static Reference<Object> pending = null;
private static Lock lock = new Lock();
- referent 表示该对象引用的对象实例,在创建引用时就需要指定该实例
- queue 对象触发回收时需要通知的队列,当触发回收时,会将整个referent实例放入队列中,消费者可以指定队列进行消费
- next 指向引用队列中的下一个Reference实例
- discovered 维护引用列表中的下一个元素,当为最后一个元素时,该值为null
- pending 等待通知的引用链表,垃圾回收器会将即将回收的对象实例加入到链表中
- lock 锁对象,用于垃圾收集器的同步操作,防止GC和tryHandlePending同时操作pending
注意Refrence
的静态代码块
static {
ThreadGroup tg = Thread.currentThread().getThreadGroup();
// 遍历主线程组中全部线程
for (ThreadGroup tgn = tg;
tgn != null;
tg = tgn, tgn = tg.getParent());
Thread handler = new ReferenceHandler(tg, "Reference Handler");
// 为该线程设置最大的优先级
handler.setPriority(Thread.MAX_PRIORITY);
handler.setDaemon(true)<