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();經過程序或垃圾收集器來告知這個引用對象是否已經入隊;java

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

軟引用(SoftReference)

  • 軟引用經過SoftReference類實現。軟引用的生命週期比強引用短一些。只有當 JVM 認爲內存不足時,纔會去試圖回收軟引用指向的對象:即JVM 會確保在拋出 OutOfMemoryError 以前,清理軟引用指向的對象。軟引用能夠和一個引用隊列(ReferenceQueue)聯合使用,若是軟引用所引用的對象被垃圾回收器回收,Java虛擬機就會把這個軟引用(注意是引用自己這個對象(就是Reference本身,並非引用所引用的對象)加入到與之關聯的引用隊列中。後續,咱們能夠調用ReferenceQueue的poll()方法來檢查是否有它所關心的對象被回收(由於在這個隊列裏面的引用所指向的對象都被回收了)。若是隊列爲空,將返回一個null,不然該方法返回隊列中前面的一個Reference對象。bash

  • 應用場景:軟引用一般用來實現內存敏感的緩存。若是還有空閒內存,就能夠暫時保留緩存,當內存不足時清理掉,這樣就保證了使用緩存的同時,不會耗盡內存。函數

弱引用(WeakReference)

  • 弱引用經過WeakReference類實現。 弱引用的生命週期比軟引用短。在垃圾回收器線程掃描它所管轄的內存區域的過程當中,一旦發現了具備弱引用的對象,無論當前內存空間足夠與否,都會回收它的內存。因爲垃圾回收器是一個優先級很低的線程,所以不必定會很快回收弱引用的對象。弱引用能夠和一個引用隊列(ReferenceQueue)聯合使用,若是弱引用所引用的對象被垃圾回收,Java虛擬機就會把這個弱引用加入到與之關聯的引用隊列中(和引用隊列一塊兒使用同上面的軟引用)。post

  • 應用場景:弱應用一樣可用於內存敏感的緩存。spa

幻象引用(PhantomReference)

  • 幻象引用也叫虛引用,經過PhantomReference類來實現。沒法經過虛引用訪問對象的任何屬性或函數。幻象引用僅僅是提供了一種確保對象被 finalize 之後,作某些事情的機制。若是一個對象僅持有虛引用,那麼它就和沒有任何引用同樣,在任什麼時候候均可能被垃圾回收器回收。虛引用必須和引用隊列 (ReferenceQueue)聯合使用。當垃圾回收器準備回收一個對象時,若是發現它還有虛引用,就會在回收對象的內存以前,把這個虛引用加入到與之關聯的引用隊列中。程序能夠經過判斷引用隊列中是否已經加入了虛引用,來了解被引用的對象是否將要被垃圾回收。若是程序發現某個虛引用已經被加入到引用隊列,那麼就能夠在所引用的對象的內存被回收以前採起一些程序行動(和引用隊列一塊兒使用同上面軟引用跟弱引用)。線程

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

引用隊列(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,我這裏就不贅述了)
  • entry的key是弱引用從他的構造函數能夠看出,爲何是弱引用呢,由於當threadlocal對象不在使用的時候將其置位null,可是這個時候entry的key仍是指向的threadlocal對象,若是這個時候是強引用就會致使threadlocal對象沒辦法回收會形成內存泄漏,因此改爲弱引用的話當只有一個弱引用的entry的key指向threadlocal對象的時候Threadlocal對象在垃圾回收的時候就會被回收掉。(這裏涉及一些ThreadLocal的底層實現,你們能夠看我這一篇博客(juejin.im/post/5b98f3…

在強引用、軟引用、弱引用、幻象引用的介紹我引用了一些其餘博客下的評論,因爲很差貼連接就只能聲明一下吧。code

相關文章
相關標籤/搜索