天天看點

java引用隊列_java的強引用、軟引用、弱引用、幻象引用,引用隊列總結

java除了原始資料類型的變量,其他所有都是引用類型。

引用分為強引用、軟引用、弱引用、幻象引用,這幾種引用影響着對象的回收

強引用

強引用:形如Object object = new Object();這樣就是典型的強引用,被強引用引用的對象不會被垃圾收集器主動回收,JVM甯願抛出OutOfMemoryError運作時錯誤(OOM),使程式異常終止,也不會靠随意回收具有強引用的“存活”對象來解決記憶體不足的問題。對于一個普通的對象,如果沒有其他的引用關系,隻要超過了引用的作用域或者顯式地将相應強引用指派為 null,這個被引用的對象就是可以被垃圾回收器回收的(具體回收時機還是要看垃圾收集政策)。

引用(Reference類)

先在這裡說一下,軟引用(SoftReference)、弱引用(WeakReference)、幻象引用(PhantomReference)都是java.lang.ref.Reference的子類,這個Reference類主要有4個方法 void clean();清除此參考對象。(此方法僅由 Java 代碼調用; 當垃圾收集器清除引用時,它直接執行,而不調用此方法。)

boolean enqueue();将此引用對象添加到其注冊的隊列(如果有)。

T get();傳回此引用對象的訓示。(通過這個方法可以傳回Reference所引用的對象,可以重新變成強引用)

例如:軟引用引用的一個對象

MyObject aRef = new MyObject();

SoftReference aSoftRef=new SoftReference(aRef);

aRef = null;

//現在隻有一個軟引用指向MyObject的這個對象,

//如果這個對象還沒有被回收,可以把他再次變為強引用

if(aSoftRef.get() != null)

MyObject bRef = aSoftRef.get();

//這個時候MyObject這個對象又變成強引用

複制代碼

boolean isEnqueued();通過程式或垃圾收集器來告知這個引用對象是否已經入隊;

其中enqueue 和 isEnqueued 這兩個方法涉及到引用隊列,我們後面會講到。這裡就先不解釋,留個印象就行。

軟引用(SoftReference)

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

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

弱引用(WeakReference)

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

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

幻象引用(PhantomReference)

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

應用場景:可用來跟蹤對象被垃圾回收器回收的活動,當一個虛引用關聯的對象被垃圾收集器回收之前會收到一條系統通知

引用隊列(ReferenceQueue)

Reference對象已經不再具有存在的價值,需要一個适當的清除機制,避免大量SoftReference對象帶來的記憶體洩漏。在java.lang.ref包裡還提供了ReferenceQueue。

前面說到在使用軟引用、虛引用、幻象引用的時候可以指定一個引用隊列,在引用所引用的對象被回收後引用本身就會進入引用隊列。 使用例子如下

ReferenceQueue queue = new ReferenceQueue();

SoftReference ref=new SoftReference(aMyObject,queue);

複制代碼

通過引用隊列可以看到哪些Reference對象所引用的對象已經被回收,當調用引用隊列的poll()方法就可以傳回除隊列中的失去所引用對象的Reference對象

利用這個方法,我們可以檢查哪個SoftReference所軟引用的對象已經被回收。于是我們可以把這些失去所軟引用的對象的SoftReference對象清除掉。

SoftReference ref = null;

while ((ref = (EmployeeRef) q.poll()) != null) {

// 清除ref

}

複制代碼

一些應用

軟引用和弱引用可以用來做一些記憶體敏感的緩存,空間足夠的時候就緩存對象,不夠的時候就回收,不會抛出ome(記憶體溢出異常,網上有很多這種小demo,我這裡就不贅述了)

在ThreadLocal中使用了弱引用,大概就是ThreadLocalMap中的Entry 對key是弱引用,因為當value沒被除ThreadLocal之外的其他強引用引用時,如果Entry對value是強引用那麼就會造成value沒辦法被回收,可能導緻oem,換成弱引用的話就不會出現由于Entry的引用而導緻value沒辦法被回收。(這裡設計一些ThreadLocal的底層實作,大家可以看我這一篇部落格( juejin.im/post/5b98f3…

在強引用、軟引用、弱引用、幻象引用的介紹我引用了一些其他部落格下的評論,由于不好貼連結就隻能聲明一下吧。