從JDK1.2版本開始,把對象的引用分爲四種級別,從而使程序能更加靈活的控制對象的生命週期。這四種級別由高到低依次爲:強引用、軟引用、弱引用和虛引用。java
1.強引用緩存
本章前文介紹的引用實際上都是強引用,這是使用最廣泛的引用。若是一個對象具備強引用,那就 相似於必不可少的生活用品,垃圾回收器毫不會回收它。當內存空 間不足,Java虛擬機寧願拋出OutOfMemoryError錯誤,使程序異常終止,也不會靠隨意回收具備強引用的對象來解決內存不足問題。this
2.軟引用(SoftReference)線程
若是一個對象只具備軟引用,那就相似於可有可物的生活用品。若是內存空間足夠,垃圾回收器就不會回收它,若是內存空間不足了,就會回收這些對象的內存。只要垃圾回收器沒有回收它,該對象就能夠被程序使用。軟引用可用來實現內存敏感的高速緩存。orm
軟引用能夠和一個引用隊列(ReferenceQueue)聯合使用,若是軟引用所引用的對象被垃圾回收,Java虛擬機就會把這個軟引用加入到與之關聯的引用隊列中。對象
3.弱引用(WeakReference)生命週期
若是一個對象只具備弱引用,那就相似於可有可物的生活用品。 弱引用與軟引用的區別在於:只具備弱引用的對象擁有更短暫的生命週期。在垃圾回收器線程掃描它 所管轄的內存區域的過程當中,一旦發現了只具備弱引用的對象,無論當前內存空間足夠與否,都會回收它的內存。不過,因爲垃圾回收器是一個優先級很低的線程, 所以不必定會很快發現那些只具備弱引用的對象。隊列
弱引用能夠和一個引用隊列(ReferenceQueue)聯合使用,若是弱引用所引用的對象被垃圾回收,Java虛擬機就會把這個弱引用加入到與之關聯的引用隊列中。內存
4.虛引用(PhantomReference)ci
"虛引用"顧名思義,就是形同虛設,與其餘幾種引用都不一樣,虛引用並不會決定對象的生命週期。若是一個對象僅持有虛引用,那麼它就和沒有任何引用同樣,在任什麼時候候均可能被垃圾回收。
虛 引用主要用來跟蹤對象被垃圾回收的活動。虛引用與軟引用和弱引用的一個區別在於:虛引用必須和引用隊列(ReferenceQueue)聯合使用。當垃 圾回收器準備回收一個對象時,若是發現它還有虛引用,就會在回收對象的內存以前,把這個虛引用加入到與之關聯的引用隊列中。程序能夠經過判斷引用隊列中是 否已經加入了虛引用,來了解被引用的對象是否將要被垃圾回收。程序若是發現某個虛引用已經被加入到引用隊列,那麼就能夠在所引用的對象的內存被回收以前採起必要的行動。
在本書中,"引用"既能夠做爲動詞,也能夠做爲名詞,讀者應該根據上下文來區分"引用"的含義。
在java.lang.ref包中提供了三個類:SoftReference類、WeakReference類和PhantomReference 類,它 們分別表明軟引用、弱引用和虛引用.ReferenceQueue類表示引用隊列,它能夠和這三種引用類聯合使用,以便跟蹤Java虛擬機回收所引用的對 象的活動.如下程序建立了一個String對象、ReferenceQueue對象和WeakReference對象:
//建立一個強引用
String str = new String(「hello」);
//建立引用隊列, 爲範型標記,代表隊列中存放String對象的引用
ReferenceQueue rq = new ReferenceQueue();
//建立一個弱引用,它引用「hello」對象,而且與rq引用隊列關聯
//爲範型標記,代表WeakReference會弱引用String對象 WeakReference wf = new WeakReference(str, rq);
以上程序代碼執行完畢,內存中引用與對象的關係如圖11-10所示.
圖11-10 "hello"對象同時具備強引用和弱引用
在圖11-10中,帶實線的箭頭表示強引用,帶虛線的箭頭表示弱引用。從圖中能夠看出,此時"hello"對象被str強引用,而且被一個WeakReference對象弱引用,所以"hello"對象不會被垃圾回收。
在如下程序代碼中,把引用「hello」對象的str變量置爲null,而後再經過WeakReference弱引用的get()方法得到「hello」對象的引用:
String str = new String(「hello」);
//① ReferenceQueue rq = new ReferenceQueue();
//② WeakReference wf = new WeakReference(str, rq);
//③ str=null; //④取消「hello」對象的強引用 String str1=wf.get();
//⑤假如「hello」對象沒有被回收,str1引用「hello」對象
//假如「hello」對象沒有被回收,rq.poll()返回null Reference ref=rq.poll();
//⑥
執行完以上第④行後,內存中引用與對象的關係如圖11-11所示,此 時「hello」對象僅僅具備弱引用,所以它有可能被垃圾回收.假如它尚未被垃圾回收,那麼接下來在第⑤行執行wf.get()方法會返 回「hello」對象的引用,而且使得這個對象被str1強引用.再接下來在第⑥行執行rq.poll()方法會返回null,由於此時引用隊列中沒有任 何引用.ReferenceQueue的poll()方法用於返回隊列中的引用,若是沒有則返回null.
圖11-11 "hello"對象只具備弱引用
在如下程序代碼中,執行完第④行後,「hello」對象僅僅具備弱引用.接下來兩次調用System.gc()方法,催促垃圾回收器工做,從而提 高「hello」對象被回收的可能性.假如「hello」對象被回收,那麼WeakReference對象的引用被加入到ReferenceQueue 中,接下來wf.get()方法返回null,而且rq.poll()方法返回WeakReference對象的引用.圖11-12顯示了執行完第⑧行後 內存中引用與對象的關係.
String str = new String(「hello」);
//① ReferenceQueue rq = new ReferenceQueue();
//② WeakReference wf = new WeakReference(str, rq);
//③ str=null;
//④ //兩次催促垃圾回收器工做,提升「hello」對象被回收的可能性 System.gc();
//⑤ System.gc();
//⑥ String str1=wf.get();
//⑦ 假如「hello」對象被回收,str1爲null Reference ref=rq.poll();
//⑧
圖11-12 "hello"對象被垃圾回收,弱引用被加入到引用隊列
The important part about strong references -- the part that makes them 「strong」 -- is how they interact with the garbage collector. Specifically, if an object is reachable via a chain of strong references (strongly reachable), it is not eligible for garbage collection. As you don't want the garbage collector destroying objects you're working on, this is normally exactly what you want.
package com.TestRef; import java.lang.ref.PhantomReference; import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; import java.lang.ref.WeakReference; import java.util.Map; import java.util.WeakHashMap; public class Ref {
public Ref() {
}
/**
* @param args
*/
public static void main(String[] args) {
try { //
test1(); //
test2(); //
test3(); //
test4(); //
test5();
test6();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/** 強引用,JVM的默認實現 */
public static void test1() throws InterruptedException {
Object obj = new Object();
Object strong = obj;
obj = null;
System.gc();
Thread.sleep(1000);
System.out.println(「strong=」+strong);
}
/**
* WeakReference 弱引用( 當所引用的對象在 JVM 內再也不有強引用時, GC 後weak reference 將會被自動回收)
* */
public static void test2() throws InterruptedException {
Object obj = new Object();
WeakReference wr = new WeakReference(obj);
obj = null;
System.gc();
Thread.sleep(1000);
System.out.println(「wr.get()=」+wr.get());
System.out.println(「wr=」+wr);
wr.clear();
System.out.println(「w1111r=」+wr.get());
}
/**
* SoftReference SoftReference 於 WeakReference 的特性基本一致, 最大的區別在於
* SoftReference 會盡量長的保留引用直到 JVM 內存不足時纔會被回收(虛擬機保證)
* */
public static void test3() throws InterruptedException {
Object obj = new Object();
SoftReference sr = new SoftReference(obj);
obj = null;
System.gc();
Thread.sleep(1000);
System.out.println(「sr.get()=」+sr.get());
}
/**
* PhantomReference Phantom Reference(幽靈引用) 與 WeakReference 和 SoftReference
* 有很大的不一樣, 由於它的 get() 方法永遠返回 null
* */
public static void test4() throws InterruptedException {
Object obj = new Object();
ReferenceQueue rq = new ReferenceQueue();
PhantomReference pr = new PhantomReference(obj, rq);
System.out.println(「pr.get()=」+pr.get());
}
/**
* ReferenceQueue:
* @throws InterruptedException
*/
public static void test5() throws InterruptedException {
Object obj = new Object();
ReferenceQueue rq = new ReferenceQueue();
WeakReference pr = new WeakReference(obj, rq);
System.out.println(「**pr.enqueue()=」+pr.enqueue());
System.out.println(「**pr.isEnqueued()=」+pr.isEnqueued());
System.out.println(「**pr=」+pr);
System.out.println(「**rq.poll()=」+rq.poll());
obj = null;
System.gc();
//
System.out.println(「pr.enqueue()=」+pr.enqueue());
//
System.out.println(「**pr.isEnqueued()=」+pr.isEnqueued());
//
System.out.println(「pr=」+pr); //
System.out.println(「rq.poll()=」+rq.poll());
//
System.out.println(「obj5=」+obj);
}
/**
* 使用 WeakReference 做爲 key, 一旦沒有指向 key 的強引用,
* WeakHashMap 在 GC 後將自動刪除相關的
* entry
*/
public static void test6() throws InterruptedException {
Map<object, object=""> map = new WeakHashMap<object, object="">();
Object key = new Object();
Object value = new Object();
map.put(key, value);
key = null;
//
System.out.println(「value=http://developer.51cto.com/art/201111/」+value);
//
System.out.println(「key=」+key);
//
System.out.println(「map.containsValue(value)=」+map.containsValue(value)); //
System.out.println(「map=」+map);
System.gc();
Thread.sleep(1000);
System.out.println(「value=http://developer.51cto.com/art/201111/」+value);
System.out.println(「key=」+key);
System.out.println(「map.containsValue(value)=」+map.containsValue(value));
System.out.println(「map=」+map);
}
}