1. 程式人生 > >簡單直白教你理解Java中四大引用強引用,軟引用,弱引用,虛引用

簡單直白教你理解Java中四大引用強引用,軟引用,弱引用,虛引用

我屬於自學型的,所以知識不夠系統,只能是一邊兒工作一邊查漏補缺,在此要對那些寫技術文章的人由衷的說句謝謝,謝謝各位大神們的分享微笑

ONE,強引用(StrongReference)

概念介紹:

在此說明一下,StrongReference只是對強引用的一個稱呼,但是強引用沒有對應的實體類。使用強引用的物件就算是記憶體出現outofmemory(記憶體溢位)

的異常也不會回收。也就是說該物件永遠不會被垃圾回收器回收,不論記憶體是否充足。平常程式碼中用的最多的就是強引用。

Demo驗證:

    static Object object = new Object();
.......................................
   /**
     * 強引用
     */
    public static void testStrongReference(){
        Object obj = object;
        object = null;
        System.gc();
        System.out.print("after system.gc-strongReference---obj = " + obj);
    }

輸出結果


在該demo中obj就是使用的預設的強引用,雖然obj所指向的物件被置為null,但gc不會回收該強引用物件

TWO,軟引用(SoftReference)

概念介紹:

軟引用有對應的實體列為SoftReference,使用軟引用引用的物件只有在程式發生oom異常前才會回收,也就是說如果記憶體充足永遠不會被回收,只有在記憶體不足時才會回收,很好的避免oom,非常適合做快取。

Demo驗證

 /**
     * 軟引用
     */
    public static void testSoftReference(){

       

       SoftReference<Object> obj = new SoftReference<>(object);

       object = null; 
       System.gc(); 
       System.out.print("after system.gc---softReference = " + obj); }



由控制檯的輸出結果可以看到,雖然軟引用引用的物件被清空,但是由於記憶體充足,就算是執行了gc也不會被回收。

小結一下:由以上的demo可以看到軟引用和強引用在記憶體充足的情況下是一樣的都不會被回收,只有在記憶體不足時軟引用才會被及時回收避免oom異常,而強引用卻很霸道堅決不回收。這樣分析來看,使用軟引用可以很好的避免oom異常,適合做一些快取工作

THREE,弱引用(WeakReference)

概念介紹:弱引用對應的實體類為WeakReference,這個概念介紹起來有點兒麻煩,可以參考demo理解再總結

Demo驗證:

第一種情況,如果把弱引用所引用的物件置為null,但不進行gc,弱引用的get到的會是null嗎?

 public static void testWeakReference(){
        WeakReference<Object> weakReference = new WeakReference<Object>(object);
        WeakReference<Object>  weakReferenceStr = new WeakReference<Object>(str);
        object = null;
        str = null;
//        System.gc();
        System.out.println("after system.gc---weakReference = " + weakReference.get());
        System.out.print("after system.gc---weakReferenceStr = " + weakReferenceStr.get());
    }

輸出結果為:
after system.gc---weakReference = [email protected]
after system.gc---weakReferenceStr = strTest
Process finished with exit code 0

可以看到如果不進行gc,弱引用物件在記憶體充足的情況下是不會回收的,不論所引用的物件是否為null
第二種情況,不對所引用的物件置為null,直接進行gc

  public static void testWeakReference(){
        WeakReference<Object> weakReference = new WeakReference<Object>(object);
        WeakReference<Object>  weakReferenceStr = new WeakReference<Object>(str);
//        object = null;
//        str = null;
        System.gc();
        System.out.println("after system.gc---weakReference = " + weakReference.get());
        System.out.print("after system.gc---weakReferenceStr = " + weakReferenceStr.get());
    }

輸出結果為

after system.gc---weakReference = [email protected]
after system.gc---weakReferenceStr = strTest
Process finished with exit code 0


可以看到,此時所引用的物件不為null,所以在進行gc回收時不會回收弱引用物件。由此可以看出弱引用跟物件的生命週期有關,在物件不為null時,垃圾回收器不會回收弱引用

第三種情況

    public static void testWeakReference(){
        WeakReference<Object> weakReference = new WeakReference<Object>(object);
        WeakReference<Object>  weakReferenceStr = new WeakReference<Object>(str);
        object = null;
        str = null;
        System.gc();
        System.out.println("after system.gc---weakReference = " + weakReference.get());
        System.out.print("after system.gc---weakReferenceStr = " + weakReferenceStr.get());
    }

輸出結果
after system.gc---weakReference = null
after system.gc---weakReferenceStr = strTest
Process finished with exit code 0

在這裡說明一下str物件的定義方式
static String str = "strTest";

可以看到,使用new的方式構造的物件在置為null後,所對應的弱引用被回收,但是使用賦值的方式所獲取的物件置為null後,所對應的弱引用沒有被回收,這是為什麼呢?這裡暫且TODO該問題,把四大引用總結完後再研究

{add 2016-11-15

這是因為gc不清理常量池裡的垃圾,所以所引用的內容不為null

}

綜合以上三種情況,可以對弱引用下一個結論了,弱應用與物件的生命週期有關。在進行垃圾回收時,如果所引用的物件為null,則不論記憶體是否充足都會被回收,否則不會被回收。當然當記憶體不足時會直接被回收。

FOUR,虛引用(PhantonReference)

概念介紹,虛引用對應的實體類為PhantonReference。虛引用不論所引用的物件是不是null,不論記憶體空間是否充足,都會被垃圾回收器回收

Demo驗證

 public static void testPhantonReference(){
        ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
        PhantomReference<Object> phantomReference = new PhantomReference<>(object,referenceQueue);
        PhantomReference<Object> phantomReferenceStr = new PhantomReference<>(str,referenceQueue);
//        object = null;
//        str = null;
        System.gc();
        System.out.println("after system.gc---phantomReference = " + phantomReference.get());
        System.out.print("after system.gc---phantomReferenceStr = " + phantomReferenceStr.get());
    }

輸出結果如下
after system.gc---phantomReference = null
after system.gc---phantomReferenceStr = null
Process finished with exit code 0


可以看到,只要進行垃圾回收,虛引用就會被回收

總結:

對於垃圾回收器回收的順序為

虛引用---弱引用----軟引用---強引用。

多使用軟引用做快取可以很好地避免oom.