1. 程式人生 > >軟引用、弱引用和虛引用

軟引用、弱引用和虛引用

一般來說,我們建立一個一般的物件,如:
Cow cow = new Cow();
這就是變數cow就是強引用,是強可觸及的,和所有區域性變數一樣,對垃圾收集器來說,這是一個根節點。
#垃圾收集器的根節點的引用和強引用的物件包含的引用都是強引用。

在java的原始碼中,有這麼幾個類

-java.lang.ref
 +SoftReference<T>.java
 +WeakReference<T>.java
 +PhantomReference<T>.java
 +ReferenceQueue<T>.java
 +Reference<T>.java

其中,軟引用(SoftReference)、弱引用(WeakReference)和虛引用(PhantomReference),
它們都繼承父類Reference,都有泛型<T>,T即為它們封裝的物件t,可以通過建構函式來傳封裝物件t;
ReferenceQueue是Reference的一個屬性域,可通過建構函式來傳這個域值,當垃圾收集器要回收封裝物件T,會呼叫
父類Reference的clear(),這樣可以切斷封裝物件跟引用物件的關係,然後呼叫ReferenceQueue.enqueue(Reference<? extends ? super T> r)方法新增Reference引用到佇列中。
這樣,通過父類Reference.isEnqueued()便可知道封裝物件是否已經被垃圾收集器回收,
若想取得封裝的物件T,可呼叫父類Reference.get()方法,如果封裝物件還沒被回收,則會返回非null,不過對於虛引用,get()方法總會返回null的,這點需要注意。

##軟引用物件
Cow cow = new Cow("niuniu");
java.lang.ref.ReferenceQueue<Cow> queue = new ReferenceQueue<Cow>();
java.lang.ref.SoftReference<Cow> softReference = new SoftReference<Cow>(cow, queue);
cow = null;
queue = null;

//softReference.clear();
//==>>this.referent = null; this:means SoftReference Object
//softReference.enqueue();
//softReference.isEnqueued();

##弱引用物件
Cow cow2 = new Cow("niuniu2");
ReferenceQueue<Cow> queue2 = new ReferenceQueue<Cow>();
java.lang.ref.WeakReference<Cow> weakReference = new WeakReference<Cow>(cow2, queue2);
cow2 = null;
queue2 = null;

##虛引用物件
Cow cow3 = new Cow("niuniu3");
ReferenceQueue<Cow> queue3 = new ReferenceQueue<Cow>();
java.lang.ref.PhantomReference<Cow> phantomReference = new PhantomReference<Cow>(cow3, queue3);
cow3 = null;
queue3 = null;

軟可觸及的
物件不是強可觸及的,即不是強引用的物件,但可以從根節點通過一個或多個(未被清除的)軟引用物件觸及的。垃圾收集器只有在記憶體不夠時,即會在丟擲OutOfMemeryError之前,回收軟引用觸及的封裝物件;
弱可觸及的
物件不是強可觸及的也不是軟可觸及的,但可以從根節點通過一個或多個(未被清除的)弱引用物件觸及的。垃圾收集器在掃描可回收的物件時,只要掃描到弱引用封裝的物件,不管虛擬機器的記憶體夠不夠用,都定會將該封裝的物件回收;java對弱引用,還提供了WeakHashMap<K, V>來儲存弱可觸及的物件,其中WeakHashMap的Entry便是繼承了WeakReference
private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> {
        V value;
        int hash;
        Entry<K,V> next;

        /**
         * Creates new entry.
         */
        Entry(Object key, V value,
              ReferenceQueue<Object> queue,
              int hash, Entry<K,V> next) {
            super(key, queue);
            this.value = value;
            this.hash  = hash;
            this.next  = next;
        }
        //...
}

虛可觸及的
物件既不是強可觸及、軟可觸及的,也不是弱可觸及的,但可以從根節點通過一個或多個(未被清除的)虛引用物件觸及的,它和軟引用、弱引用區別:它必須有引用佇列聯合使用,也即是說建構函式必須傳ReferenceQueu引用佇列。虛引用,在任何時候都可以回收虛引用的封裝物件,它跟軟引用、弱引用不同,在任何時候,get()方法都會返回null,不過,垃圾收集器會先PhantomReference物件新增到ReferenceQueue佇列中,然後再把回收虛可觸及的物件,這點也是跟軟、弱引用不同的。