Java面試問題總結——介紹一下什麼是強引用和弱引用?它們的用法是什麼?

這個問題是阿里菜鳥網絡一面面試官的提問,由於個人準備不夠充分以及知識儲備不足沒有答出問題根本。其實這個問題是Java面試中比較常見的問題,按難度來劃分的話應該只是中等難度,之前也瞭解過它們的區別,但是實際開發過程幾乎很少使用導致只是純粹記憶,本文將系統的整理強引用,軟引用,弱引用和虛引用的區別,並結合具體場景探究一下它們的用法。

一、什麼是強引用,軟引用,弱引用,虛引用?

JDK1.2 以前,如果一個對象不被任何變量引用,則程序無法再次使用這個對象,這個對象最終會被 GC(GabageCollection:垃圾回收)。但是如果之後可能還會用到這個對象,就只能去新建一個了,這其實就降低了 JVM 性能,沒有達到最大的優化策略。

從JDK1.2開始,提供了四種類型的引用:強引用(StrongReference)、軟引用(SoftReference)、弱引用(WeakReference)和虛引用(PhantomReference)。主要有兩個目的:1.可以在代碼中決定某些對象的生命週期;2.優化JVM的垃圾回收機制。

1.強引用(StrongReference)

強引用是程序代碼之中普遍存在的,我們一般創建對象的過程都是強引用,如下面代碼。

    Object object = new Object();
    String str = "123";  

如果某個對象有強引用與之關聯,Java虛擬機(JVM)必定不會回收這個對象,即使在內存不足的情況下,JVM寧願拋出OutOfMemory 錯誤也不會回收這種對象。基於上述情況,我們在使用完對象後如果想讓 JVM 回收對象需要將對象弱化,具體操作是將其引用置爲null。(補充說明:局部方法內的強引用會隨着方法的結束退棧而自動清除引用,全局變量需要在不使用時置null

    Object strongReference = new Object();
    strongReference = null;

Java集合類的強引用弱化方式不能採取置 null 方式,因爲這種方式強引用依然存在,只有採用 clear()方法內存數組中存放的引用類型進行內存釋放,這樣纔可以及時釋放內存。

        ArrayList<Integer> arrays = new ArrayList<>(10);
        arrays.add(1);
        arrays.add(2);
        arrays.add(3);
        arrays.clear();//不使用時 clear 清除數組

查看 ArrayList 的 clear 方法的源碼發現是遍歷元素數組將每個元素置爲 null ,即  elementData[i] = null 。

2.軟引用(SoftReference

軟引用是用來描述一些有用但並不是必需的對象,適合用來實現緩存(比如瀏覽器的‘後退’按鈕使用的緩存),JVM內存空間充足的時候將數據緩存在內存中,如果空間不足了就將其回收掉。

    // 強引用
    String strongReference = new String("123");
    // 軟引用,"456"這個String對象包含一個強引用 str 和弱引用 softReference 
    String str = new String("456");
    SoftReference<String> softReference = new SoftReference<String>(str);

軟引用可以和一個引用隊列(ReferenceQueue)聯合使用。如果軟引用所引用對象被垃圾回收,JAVA虛擬機就會把這個軟引用加入到與之關聯的引用隊列中。

    ReferenceQueue<String> referenceQueue = new ReferenceQueue<>();
    String str = new String("abc");
    SoftReference<String> softReference = new SoftReference<>(str, referenceQueue);

    str = null;//去掉 str 的強引用
    System.gc();// Notify GC

    System.out.println(softReference.get()); // abc

    Reference<? extends String> reference = referenceQueue.poll();
    System.out.println(reference); //null

軟引用對象是在jvm內存不夠的時候纔會被回收,我們調用System.gc()方法只是起通知作用,JVM什麼時候掃描回收對象是JVM自己的狀態決定的。即使掃描到軟引用對象也不一定會回收它,只有內存不夠的時候JVM纔會回收。

3.弱引用(WeakReference)

弱引用也是用來描述非必需對象的,當JVM進行垃圾回收時,無論內存是否充足,都會回收被弱引用關聯的對象,在java中用java.lang.ref.WeakReference類來表示。

弱引用與軟引用的區別在於:只具有弱引用的對象擁有更短暫的生命週期,它只能生存到下一次垃圾收集發生之前。當垃圾回收器掃描到只具有弱引用的對象時,無論當前內存空間是否足夠,都會回收它。不過,由於垃圾回收器是一個優先級很低的線程,因此不一定會很快發現那些只具有弱引用的對象。

    String str = new String("abc");
    WeakReference<String> weakReference = new WeakReference<>(str);
    str = null;//去掉強引用

如果一個對象是偶爾(很少)的使用,並且希望在使用時隨時就能獲取到,但又不想影響此對象的垃圾收集,那麼我們應該用Weak Reference來標記此對象。

弱引用也可以和一個引用隊列(ReferenceQueue)聯合使用,如果弱引用所引用的對象被垃圾回收,Java虛擬機就會把這個弱引用加入到與之關聯的引用隊列中。

    String person = new String ("123");
    ReferenceQueue<Person> queue = new ReferenceQueue<>();
    WeakReference<Person> weakReference = new WeakReference<Person>(person, queue);

    person = null;//去掉強引用

4.虛引用(PhantomReference)

與其他三種引用都不同,虛引用並不會決定對象的生命週期。如果一個對象僅持有虛引用,那麼它就和沒有任何引用一樣,在任何時候都可能被垃圾回收。

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

    String str= new String();
    ReferenceQueue queue = new ReferenceQueue ();
    // 創建虛引用,要求必須與一個引用隊列關聯
    PhantomReference pr = new PhantomReference (str, queue); 

虛引用必須和引用隊列(ReferenceQueue)聯合使用。當垃圾回收器準備回收一個對象時,如果發現它還有虛引用,就會在回收對象的內存之前,把這個虛引用加入到與之關聯的引用隊列中。

程序可以通過判斷引用隊列中是否已經加入了虛引用,來了解被引用的對象是否將要進行垃圾回收。如果程序發現某個虛引用已經被加入到引用隊列,那麼就可以在所引用的對象的內存被回收之前採取必要的行動。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章