问题
在分析前,先抛几个问题?
1.网上大多数文章对于软引用的介绍是:在内存不足的时候才会被回收,那内存不足是怎么定义的?什么才叫内存不足?
2.网上大多数文章对于虚引用的介绍是:形同虚设,虚引用并不会决定对象的生命周期。主要用来跟踪对象被垃圾回收器回收的活动。真的是这样吗?
3.虚引用在Jdk中有哪些场景下用到了呢?
Reference
我们先看下Reference.java中的几个字段public abstract class Reference { //引用的对象
private T referent;
//回收队列,由使用者在Reference的构造函数中指定
volatile ReferenceQueue super T> queue; //当该引用被加入到queue中的时候,该字段被设置为queue中的下一个元素,以形成链表结构
volatile Reference next; //在GC时,JVM底层会维护一个叫DiscoveredList的链表,存放的是Reference对象,discovered字段指向的就是链表中的下一个元素,由JVM设置
transient private Reference discovered;
//进行线程同步的锁对象
static private class Lock { } private static Lock lock = new Lock(); //等待加入queue的Reference对象,在GC时由JVM设置,会有一个java层的线程(ReferenceHandler)源源不断的从pending中提取元素加入到queue
private static Reference pending = null;
}
一个Reference对象的生命周期如下:
image
主要分为Native层和Java层两个部分。
Native层在GC时将需要被回收的Reference对象加入到DiscoveredList中(代码在referenceProcessor.cpp中process_discovered_references方法),然后将DiscoveredList的元素移动到PendingList中(代码在referenceProcessor.cpp中enqueue_discovered_ref_helper方法),PendingList的队首就是Reference类中的pending对象。 具体代码就不分析了,有兴趣的同学可以看看这篇文章。
看看Java层的代码private static class ReferenceHandler extends Thread {
... public void run() { while (true) {
tryHandlePending(true);
}
}
}
static boolean tryHandlePending(boolean waitForNotify) {
Reference r;
Cleaner c; try { synchronized (lock) { if (pending != null) {
r = pending; //如果是Cleaner对象,则记录下来,下面做特殊处理
c = r instanceof Cleaner ? (Cleaner) r : null; //指向PendingList的下一个对象
pending = r.discovered;
r.discovered = null;
} else { //如果pending为null就先等待