天天看點

《我要進大廠系列 七》-談談你對強軟弱虛四種引用了解?

文章目錄

  • ​​1.引言​​
  • ​​2.強引用​​
  • ​​3.軟引用​​
  • ​​4.弱引用​​
  • ​​5.虛引用​​

1.引言

其實強引用、軟引用、弱引用、虛引用這四個概念非常簡單好記。

在開頭先總結一下這四個引用的特點吧。

強引用:gc時不會回收
軟引用:隻有在記憶體不夠用時,gc才會回收
弱引用:隻要gc就會回收
虛引用:是否回收都找不到引用的對象,僅用于管理直接記憶體      

接下來詳細看看這四種引用,結合代碼,深刻的體會一下。

2.強引用

即我們平時最常見的:

Object object = new Object();      
《我要進大廠系列 七》-談談你對強軟弱虛四種引用了解?

隻要一個對象有強引用,垃圾回收器就不會進行回收。即便記憶體不夠了,抛出OutOfMemoryError異常也不會回收。

/**
 * 一個對象
 * 重寫finalize方法,可以知道已經被回收的狀态
 *
 * @author 
 * @date 2020-05-23
 */
public class OneObject {
    @Override
    protected void finalize() throws Throwable {
        System.out.println("啊哦~OneObject被回收了");
    }
}

/**
 * 強引用例子
 *
 * @author 
 * @date 2020-05-23
 */
public class ShowStrongReference {
    public static void main(String[] args) {
        // 直接new一個對象,就是強引用
        OneObject oneObject = new OneObject();
        System.out.println("輸出對象位址:" + oneObject);
        System.gc();
        System.out.println("第一次gc後輸出對象位址:" + oneObject);
        oneObject = null;
        System.gc();
        System.out.println("置為null後gc輸出對象位址:" + oneObject);
    }
}      

執行代碼,可以看到以下輸出:

輸出對象位址:com.esparks.pandora.learning.references.OneObject@72ea2f77
第一次gc後輸出對象位址:com.esparks.pandora.learning.references.OneObject@72ea2f77
置為null後gc輸出對象位址:null
啊哦~OneObject被回收了      

3.軟引用

需要通過SoftReference對象實作:

SoftReference<OneObject> oneObjectSr = new SoftReference<>(new OneObject());      
《我要進大廠系列 七》-談談你對強軟弱虛四種引用了解?

當記憶體足夠的時候,垃圾回收器不會進行回收。當記憶體不夠時,就會回收隻存在軟引用的對象釋放記憶體。

常用于本地緩存處理。

/**
 * 軟引用
 * 記憶體不夠了就會回收
 * 注意,運作時需要保證heap大小為35m,即小于實驗中全部對象的大小,才能觸發gc
 * -Xmx35m
 *
 * @author 
 * @date 2020-05-23
 */
public class ShowSoftReference {
    public static void main(String[] args) {
        // 我們需要通過SoftReference來建立軟引用
        SoftReference<OneObject> oneObjectSr = new SoftReference<>(new OneObject());
        // 我們這裡建立一個大小為20m的數組
        SoftReference<byte[]> arraySr = new SoftReference<>(new byte[1024 * 1024 * 20]);
        System.out.println("軟引用對象oneObjectSr的位址:" + oneObjectSr);
        System.out.println("通過oneObjectSr關聯的oneObject對象的位址:" + oneObjectSr.get());
        System.out.println("數組的位址:" + arraySr.get());
        System.gc();
        System.out.println("正常gc一次之後,oneObject對象并沒有回收。位址" + oneObjectSr.get());

        // 再建立另一個大小為20m的數組,這樣heap就不夠大了,進而系統自動gc。如果依舊不夠,會把已有的軟引用關聯的對象都回收掉。
        System.out.println("建立另一個大小為20m的數組otherArray");
        byte[] otherArray = new byte[1024 * 1024 * 20];
        System.out.println("otherArray的位址:" + otherArray);

        // gc後,軟引用對象還在,但是通過軟引用對象建立的對象就被回收了
        System.out.println("現在srObject的位址:" + arraySr);
        System.out.println("現在srObject中oneObject對象的位址:" + arraySr.get());
        System.out.println("剛才的數組對象也被回收啦,位址:" + arraySr.get());
    }
}      

執行代碼,可以看到以下輸出:

軟引用對象oneObjectSr的位址:java.lang.ref.SoftReference@72ea2f77
通過oneObjectSr關聯的oneObject對象的位址:com.esparks.pandora.learning.references.OneObject@33c7353a
數組的位址:[B@681a9515
正常gc一次之後,oneObject對象并沒有回收。位址com.esparks.pandora.learning.references.OneObject@33c7353a
建立另一個大小為20m的數組otherArray
啊哦~OneObject被回收了
otherArray的位址:[B@3af49f1c
現在srObject的位址:java.lang.ref.SoftReference@19469ea2
現在srObject中oneObject對象的位址:null
剛才的數組對象也被回收啦,位址:null      

4.弱引用

需要通過WeakReference對象實作:

WeakReference<OneObject> oneObjectWr = new WeakReference<>(new OneObject());      
《我要進大廠系列 七》-談談你對強軟弱虛四種引用了解?

隻要發生gc,就會回收隻存在弱引用的對象。

常用于Threadlocal。

/**
 * 弱引用
 * 隻要gc就會回收
 *
 * @author 
 * @date 2020-05-23
 */
public class ShowWeakReference {
    public static void main(String[] args) {
        // 我們需要通過WeakReference來建立弱引用
        WeakReference<OneObject> objectWr = new WeakReference<>(new OneObject());
        System.out.println("弱引用objectWr的位址:" + objectWr);
        System.out.println("弱引用objectWr關聯的oneObject對象的位址:" + objectWr.get());

        System.gc();

        // gc後,弱引用對象還在,但是通過弱引用對象建立的對象就被回收了
        System.out.println("gc後,弱引用objectWr的位址:" + objectWr);
        System.out.println("gc後,弱引用objectWr關聯的oneObject對象的位址:" + objectWr.get());
    }
}      

5.虛引用

需要通過PhantomReference對象和ReferenceQueue實作:

private ReferenceQueue<OneObject> queue = new ReferenceQueue<>();
PhantomReference<OneObject> oneObjectPr = new PhantomReference<>(new OneObject(), queue);      
《我要進大廠系列 七》-談談你對強軟弱虛四種引用了解?

無論是否gc,其實都擷取不到通過PhantomReference建立的對象。

其僅用于管理直接記憶體,起到通知的作用。

/**
 * 虛引用
 * 隻用于管理直接記憶體,起到通知的作用
 *
 * @author 
 * @date 2020-05-23
 */
public class ShowPhantomReference {
    /**
     * 虛引用需要的隊列
     */
    private static final ReferenceQueue<OneObject> QUEUE = new ReferenceQueue<>();

    public static void main(String[] args) {
        // 我們需要通過WeakReference來建立虛引用
        PhantomReference<OneObject> objectPr = new PhantomReference<>(new OneObject(), QUEUE);
        System.out.println("虛引用objectPr的位址:" + objectPr);
        System.out.println("虛引用objectPr關聯的oneObject對象的位址:" + objectPr.get());

        // 觸發gc,然後檢查隊列中是否有虛引用
        while (true) {
            System.gc();
            Reference<? extends OneObject> poll = QUEUE.poll();
            if (poll != null) {
                System.out.println("隊列裡找到objectPr啦" + poll);
                break;
            }
        }
    }
}      
虛引用objectPr的位址:java.lang.ref.PhantomReference@72ea2f77
虛引用objectPr關聯的oneObject對象的位址:null
啊哦~OneObject被回收了
隊列裡找到objectPr啦java.lang.ref.PhantomReference@72ea2f77      

繼續閱讀