Java 對象引用方式 —— 強引用、軟引用、弱引用和虛引用

Java中負責內存回收的是JVM。經過JVM回收內存,咱們不須要像使用C語音開發那樣操心內存的使用,可是正由於不用操心內存的時候,也會致使在內存回收方面存在不夠靈活的問題。爲了解決內存操做不靈活的問題,咱們能夠經過了解Java的引用方式來解決這個問題。java

在JDK1.2之前的版本中,當一個對象不被任何變量引用,那麼程序就沒法再使用這個對象。也就是說,只有對象處於可觸及狀態,程序才能使用它。這就像在平常生活中,從商店購買了某樣物品後,若是有用,就一直保留它,不然就把它扔到垃圾箱,由清潔工人收走。若是物品已經被扔到垃圾箱,想再把它撿回來使用就不可能了。但有時候狀況並不這麼簡單,某些物品如今已經無用了,保留它會佔空間,可是馬上扔掉它也不划算,由於也許未來還會派用場。對於這樣的無關緊要的物品,一種折衷的處理辦法是:若是家裏空間足夠,就先把它保留在家裏,若是家裏空間不夠,即便把家裏全部的垃圾清除,仍是沒法容納那些必不可少的生活用品,那麼再扔掉這些無關緊要的物品。算法

從JDK1.2版本開始,把對象的引用分爲四種級別,從而使程序能更加靈活的控制對象的生命週期。這四種級別由高到低依次爲:強引用、軟引用、弱引用和虛引用。爲了解決內存操做不靈活這個問題,咱們能夠嘗試使用軟引用。緩存

1.強引用安全

咱們使用的大部分的引用都是強引用,這是使用最廣泛的引用。若是一個對象具備強引用,那就相似於必不可少的生活用品,垃圾回收器毫不會回收它。當內存空間不足,Java虛擬機寧願拋出OutOfMemoryError錯誤,使程序異常終止,也不會靠隨意回收具備強引用的對象來解決內存不足問題。網絡

2.軟引用(SoftReference)性能

若是一個對象只具備軟引用,那就相似於可有可物的生活用品。若是內存空間足夠,垃圾回收器就不會回收它,若是內存空間不足了,就會回收這些對象的內存。只要垃圾回收器沒有回收它,該對象就能夠被程序使用。軟引用可用來實現內存敏感的高速緩存。
軟引用能夠和一個引用隊列(ReferenceQueue)聯合使用,若是軟引用所引用的對象被垃圾回收,JAVA虛擬機就會把這個軟引用加入到與之關聯的引用隊列中。spa

3.弱引用(WeakReference)
若是一個對象只具備弱引用,那就相似於可有可物的生活用品。弱引用與軟引用的區別在於:只具備弱引用的對象擁有更短暫的生命週期。在垃圾回收器線程掃描它 所管轄的內存區域的過程當中,一旦發現了只具備弱引用的對象,無論當前內存空間足夠與否,都會回收它的內存。不過,因爲垃圾回收器是一個優先級很低的線程, 所以不必定會很快發現那些只具備弱引用的對象。 
弱引用能夠和一個引用隊列(ReferenceQueue)聯合使用,若是弱引用所引用的對象被垃圾回收,Java虛擬機就會把這個弱引用加入到與之關聯的引用隊列中。線程

4.虛引用(PhantomReference)
"虛引用"顧名思義,就是形同虛設,與其餘幾種引用都不一樣,虛引用並不會決定對象的生命週期。若是一個對象僅持有虛引用,那麼它就和沒有任何引用同樣,在任什麼時候候均可能被垃圾回收。
虛引用主要用來跟蹤對象被垃圾回收的活動。虛引用與軟引用和弱引用的一個區別在於:虛引用必須和引用隊列(ReferenceQueue)聯合使用。當垃 圾回收器準備回收一個對象時,若是發現它還有虛引用,就會在回收對象的內存以前,把這個虛引用加入到與之關聯的引用隊列中。程序能夠經過判斷引用隊列中是 否已經加入了虛引用,來了解被引用的對象是否將要被垃圾回收。程序若是發現某個虛引用已經被加入到引用隊列,那麼就能夠在所引用的對象的內存被回收以前採起必要的行動。設計

特別注意,在程序設計中通常不多使用弱引用與虛引用,使用軟引用的狀況較多,這是由於軟引用能夠加速JVM對垃圾內存的回收速度,能夠維護系統的運行安全,防止內存溢出(OutOfMemory)等問題的產生。code

如下是軟引用的代碼:

import java.lang.ref.SoftReference;  
public class Test {  
      
    public static void main(String[] args){  
        System.out.println("開始");           
        A a = new A();            
        SoftReference<A> sr = new SoftReference<A>(a);  
        a = null;  
        if(sr!=null){  
            a = sr.get();  
        }  
        else{  
            a = new A();  
            sr = new SoftReference<A>(a);  
        }          
        System.out.println("結束");     
    }        
}  
  
class A{  
    int[] a ;  
    public A(){  
        a = new int[100000000];  
    }  
}

 

Tips:由於本人目前從事的是Android方面的工做,因此在下面總結一些在Android研發中會使用到弱引用或者軟引用的地方

1.解決Handler可能形成的內存泄露 -- 使用弱引用

當使用內部類(包括匿名類)來建立Handler的時候,Handler對象會隱式地持有一個外部類對象(一般是一個Activity)的引用,否則你怎麼可能經過Handler來操做Activity中的View。而Handler一般會伴隨着一個耗時的後臺線程(例如從網絡拉取圖片)一塊兒出現,這個後臺線程在任務執行完畢(例如圖片下載完畢)以後,經過消息機制通知Handler,而後Handler把圖片更新到界面。

然而,若是用戶在網絡請求過程當中關閉了Activity,正常狀況下,Activity再也不被使用,它就有可能在GC檢查時被回收掉,但因爲這時線程還沒有執行完,而該線程持有Handler的引用(否則它怎麼發消息給Handler?),這個Handler又持有Activity的引用,就致使該Activity沒法被回收(即內存泄露),直到網絡請求結束(例如圖片下載完畢)。

2.解決圖片加載時,可能形成的內存不足問題 -- 使用軟引用

使用軟引用相對使用強引用,在圖片加載方面可以很明顯的提高性能,並減小崩潰的概率,與Lru算法指定LruCache可以更好的去管理,由於增長了根據圖片使用頻率來管理內存的算法,相比較更加合理和人性化。

 

補充:Java垃圾回收機制:

Java的垃圾回收器要負責完成3件任務:分配內存、確保被引用的對象的內存不被錯誤回收以及回收再也不被引用的對象的內存空間。垃圾回收是一個複雜並且耗時的操做。若是JVM花費過多的時間在垃圾回收上,則勢必會影響應用的運行性能。通常狀況下,當垃圾回收器在進行回收操做的時候,整個應用的執行是被暫時停止(stop-the-world)的。對於與用戶交互的應用來講,則可能但願所垃圾回收所帶來的應用停頓的時間間隔越小越好。對於這種狀況,JVM中提供了多種垃圾回收方法以及對應的性能調優參數,應用能夠根據須要來進行定製。

相關文章
相關標籤/搜索