Java中的四種引用類型

引用與對象

  每種編程語言都有本身操做內存中元素的方式,例如在 C 和 C++ 裏是經過指針,而在 Java 中則是經過「引用」。在 Java 中一切都被視爲了對象,可是咱們操做的標識符其實是對象的一個引用(reference)。html

  從JDK 1.2版本開始,把對象的引用分爲4種級別,從而使程序能更加靈活地控制對象的生命週期。這4種引用的強度依次減弱:強引用(Strong Reference)、軟引用(Soft Reference)、弱引用(Weak Reference)、虛引用(Phantom Reference)4 種。java

//建立一個引用,引用能夠獨立存在,並不必定須要與一個對象關聯
String s;

//經過這個引用標識符指向某個對象,以後即可以經過這個引用來實現操做對象了。
s = new String("abc");
System.out.println(str.toString());

  Java 中的垃圾回收機制在判斷是否回收某個對象的時候,都須要依據「引用」這個概念。
  在不一樣垃圾回收算法中,對引用的判斷方式有所不一樣:算法

    • 引用計數法:爲每一個對象添加一個引用計數器,每當有一個引用指向它時,計數器就加1,當引用失效時,計數器就減1,當計數器爲0時,則認爲該對象能夠被回收(目前在Java中已經棄用這種方式了)。
    • 可達性分析算法:從一個被稱爲 GC Roots 的對象開始向下搜索,若是一個對象到GC Roots沒有任何引用鏈相連時,則說明此對象不可用。

  

引用類型

  一、強引用

  Java中默認聲明的就是強引用,只要強引用存在,垃圾回收器將永遠不會回收被引用的對象,哪怕內存不足時,JVM也只會直接拋出OutOfMemoryError,不會去回收。若是想中斷強引用與對象之間的聯繫,能夠顯示的將強引用賦值爲null,這樣一來,JVM就能夠適時的回收對象了。例如:編程

        //只要obj還指向Object對象,Object對象就不會被回收
        Object obj = new Object();
        
        //將強引用賦值爲null後JVM能夠回收
        obj = null;

  二、軟引用

  軟引用是用來描述一些非必需但仍有用的對象。在內存足夠的時候,軟引用對象不會被回收,只有在內存不足時,GC則會回收軟引用對象,若是回收了軟引用對象以後仍然沒有足夠的內存,纔會拋出內存溢出異常。這種特性經常被用來實現緩存技術,好比網頁緩存,圖片緩存等。在 JDK1.2 以後,用java.lang.ref.SoftReference類來表示軟引用。數組

  接下來作個測試,個人內存配置以下圖:緩存

軟引用:編程語言

public static void testSoftReference() {
        for (int i = 0; i < 5; i++) {
            //建立弱引用字節數組
            byte[] buff = new byte[1024 * 1024 * 1000];
            SoftReference<byte[]> sr = new SoftReference<byte[]>(buff);
            list.add(sr);
        }

        //主動通知垃圾回收,內存不足時回收弱引用
        System.gc();

        for(int i=0; i < list.size(); i++){
            Object obj = ((SoftReference) list.get(i)).get();
            System.out.println(obj);
        }
    }
測試結果:
null
null null null [B@14ae5a5

  打印結果老是隻有最後一個對象被保留,其餘的obj全都被置空回收了。這裏就說明了在內存不足的狀況下,軟引用將會被自動回收。即便有 byte[] buff 引用指向對象, 且 buff 是一個strong reference, 可是 SoftReference sr 指向的對象仍然被回收了,這是由於Java的編譯器發現了在以後的代碼中, buff 已經沒有被使用了, 因此自動進行了優化。測試

強引用:優化

public static void testSoftReference1() {
        //強引用
        byte[] buff = null;

        for (int i = 0; i < 5; i++) {
            buff = new byte[1024 * 1024 * 1000];
            SoftReference<byte[]> sr = new SoftReference<byte[]>(buff);
            list.add(sr);
        }

        //主動通知垃圾回收,內存不足時回收弱引用
        System.gc();

        for(int i=0; i < list.size(); i++){
            Object obj = ((SoftReference) list.get(i)).get();
            System.out.println(obj);
        }
    }
結果:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at com.demo.ReferenceTest.testSoftReference1(ReferenceTest.java:45) at com.demo.ReferenceTest.main(ReferenceTest.java:20)

buff 會由於強引用的存在,而沒法被垃圾回收,從而拋出OOM的錯誤。this

 

  3.弱引用

  弱引用的引用強度比軟引用要更弱一些,不管內存是否足夠,只要 JVM 開始進行垃圾回收,那些被弱引用關聯的對象都會被回收。在 JDK1.2 以後,用 java.lang.ref.WeakReference 來表示弱引用。

public static void testWeakReference() {
        for (int i = 0; i < 5; i++) {
            byte[] buff = new byte[1024 * 1024 * 1000];
            WeakReference<byte[]> sr = new WeakReference<byte[]>(buff);
            list.add(sr);
        }

        //主動通知垃圾回收
        System.gc();

        for(int i=0; i < list.size(); i++){
            Object obj = ((WeakReference) list.get(i)).get();
            System.out.println(obj);
        }
    }
結果:
null
null null null null

能夠發現全部被弱引用關聯的對象都被垃圾回收了。

  弱引用與軟引用的區別在於:只具備弱引用的對象擁有更短暫的生命週期。在垃圾回收器線程掃描它所管轄的內存區域的過程當中,一旦發現了只具備弱引用的對象,無論當前內存空間足夠與否,都會回收它的內存。不過,因爲垃圾回收器是一個優先級很低的線程,所以不必定會很快發現那些只具備弱引用的對象。

 

  四、虛引用

   (1)概念

  「虛引用」顧名思義,就是形同虛設,與其餘幾種引用都不一樣,虛引用並不會決定對象的生命週期。若是一個對象僅持有虛引用,那麼它就和沒有任何引用同樣,在任什麼時候候均可能被垃圾回收器回收。

  虛引用主要用來跟蹤對象被垃圾回收器回收的活動。虛引用與軟引用和弱引用的一個區別在於:虛引用必須和引用隊列 (ReferenceQueue)聯合使用。當垃圾回收器準備回收一個對象時,若是發現它還有虛引用,就會在回收對象的內存以前,把這個虛引用加入到與之 關聯的引用隊列中。

public class PhantomReference<T> extends Reference<T> {
    /**
     * Returns this reference object's referent.  Because the referent of a
     * phantom reference is always inaccessible, this method always returns
     * <code>null</code>.
     *
     * @return  <code>null</code>
     */
    public T get() {
        return null;
    }
    public PhantomReference(T referent, ReferenceQueue<? super T> q) {
        super(referent, q);
    }
}

 

  (2)引用隊列(ReferenceQueue)

  引用隊列能夠與軟引用、弱引用以及虛引用一塊兒配合使用,當垃圾回收器準備回收一個對象時,若是發現它還有引用,那麼就會在回收對象以前,把這個引用加入到與之關聯的引用隊列中去。程序能夠經過判斷引用隊列中是否已經加入了引用,來判斷被引用的對象是否將要被垃圾回收,這樣就能夠在對象被回收以前採起一些必要的措施。

  與軟引用、弱引用不一樣,虛引用必須和引用隊列一塊兒使用。

 

 

參考地址:http://www.noobyard.com/article/p-fufinhmf-ea.html