天天看點

Java -- 每日一問:強引用、軟引用、弱引用、幻象引用有什麼差別?

Java -- 每日一問:強引用、軟引用、弱引用、幻象引用有什麼差別?

典型回答

不同的引用類型,主要展現的是對象不同的可達性(reachable)狀态和對垃圾收集的影響。

所謂強引用(“Strong” Reference),就是我們最常見的普通對象引用,隻要還有強引用指向一個對象,就能表明對象還“活着”,垃圾收集器不會碰這種對象。對于一個普通的對象,如果沒有其他的引用關系,隻要超過了引用的作用域或者顯式地将相應(強)引用指派為 null,就是可以被垃圾收集的了,當然具體回收時機還是要看垃圾收集政策。

軟引用(SoftReference),是一種相對強引用弱化一些的引用,可以讓對象豁免一些垃圾收集,隻有當 JVM 認為記憶體不足時,才會去試圖回收軟引用指向的對象。JVM 會確定在抛出 OutOfMemoryError 之前,清理軟引用指向的對象。軟引用通常用來實作記憶體敏感的緩存,如果還有空閑記憶體,就可以暫時保留緩存,當記憶體不足時清理掉,這樣就保證了使用緩存的同時,不會耗盡記憶體。

弱引用(WeakReference)并不能使對象豁免垃圾收集,僅僅是提供一種通路在弱引用狀态下對象的途徑。這就可以用來建構一種沒有特定限制的關系,比如,維護一種非強制性的映射關系,如果試圖擷取時對象還在,就使用它,否則重制執行個體化。它同樣是很多緩存實作的選擇。

對于幻象引用,有時候也翻譯成虛引用,你不能通過它通路對象。幻象引用僅僅是提供了一種確定對象被 finalize 以後,做某些事情的機制,比如,通常用來做所謂的 Post-Mortem 清理機制,我在專欄上一講中介紹的 Java 平台自身 Cleaner 機制等,也有人利用幻象引用監控對象的建立和銷毀。

高手回答

在Java語言中,除了基本資料類型外,其他的都是指向各類對象的對象引用;Java中根據其生命周期的長短,将引用分為4類。

1 強引用

特點:我們平常典型編碼Object obj = new Object()中的obj就是強引用。通過關鍵字new建立的對象所關聯的引用就是強引用。 當JVM記憶體空間不足,JVM甯願抛出OutOfMemoryError運作時錯誤(OOM),使程式異常終止,也不會靠随意回收具有強引用的“存活”對象來解決記憶體不足的問題。對于一個普通的對象,如果沒有其他的引用關系,隻要超過了引用的作用域或者顯式地将相應(強)引用指派為 null,就是可以被垃圾收集的了,具體回收時機還是要看垃圾收集政策。

2 軟引用

特點:軟引用通過SoftReference類實作。 軟引用的生命周期比強引用短一些。隻有當 JVM 認為記憶體不足時,才會去試圖回收軟引用指向的對象:即JVM 會確定在抛出 OutOfMemoryError 之前,清理軟引用指向的對象。軟引用可以和一個引用隊列(ReferenceQueue)聯合使用,如果軟引用所引用的對象被垃圾回收器回收,Java虛拟機就會把這個軟引用加入到與之關聯的引用隊列中。後續,我們可以調用ReferenceQueue的poll()方法來檢查是否有它所關心的對象被回收。如果隊列為空,将傳回一個null,否則該方法傳回隊列中前面的一個Reference對象。

應用場景:軟引用通常用來實作記憶體敏感的緩存。如果還有空閑記憶體,就可以暫時保留緩存,當記憶體不足時清理掉,這樣就保證了使用緩存的同時,不會耗盡記憶體。

3 弱引用

弱引用通過WeakReference類實作。 弱引用的生命周期比軟引用短。在垃圾回收器線程掃描它所管轄的記憶體區域的過程中,一旦發現了具有弱引用的對象,不管目前記憶體空間足夠與否,都會回收它的記憶體。由于垃圾回收器是一個優先級很低的線程,是以不一定會很快回收弱引用的對象。弱引用可以和一個引用隊列(ReferenceQueue)聯合使用,如果弱引用所引用的對象被垃圾回收,Java虛拟機就會把這個弱引用加入到與之關聯的引用隊列中。

應用場景:弱應用同樣可用于記憶體敏感的緩存。

4 虛引用

特點:虛引用也叫幻象引用,通過PhantomReference類來實作。無法通過虛引用通路對象的任何屬性或函數。幻象引用僅僅是提供了一種確定對象被 finalize 以後,做某些事情的機制。如果一個對象僅持有虛引用,那麼它就和沒有任何引用一樣,在任何時候都可能被垃圾回收器回收。虛引用必須和引用隊列 (ReferenceQueue)聯合使用。當垃圾回收器準備回收一個對象時,如果發現它還有虛引用,就會在回收對象的記憶體之前,把這個虛引用加入到與之關聯的引用隊列中。

ReferenceQueue queue = new ReferenceQueue ();

PhantomReference pr = new PhantomReference (object, queue);

程式可以通過判斷引用隊列中是否已經加入了虛引用,來了解被引用的對象是否将要被垃圾回收。如果程式發現某個虛引用已經被加入到引用隊列,那麼就可以在所引用的對象的記憶體被回收之前采取一些程式行動。