【J2SE】這才是java虛引用(PhantomReference)

來源:互聯網
上載者:User

標籤:reference   referencequeue   phantomreference   gc   java.lang.ref   

一、java.lang.ref

    java.lang.ref包規範(參看JDK API中所述內容,本文就不貼出來了)有幾個點很重要。

    1. 這個包中的類使得應用程式可以與JVM垃圾收集器進行一些互動;

    2. 引用的可達性逐漸降低:強引用、弱引用、軟引用、虛引用;

    3. 自動清除引用:只有弱引用和軟引用會自動清除引用(這表明虛引用不會自動清除),清除的時機是將引用註冊到引用隊列之前(只有當記憶體不夠用,軟引用才會被回收;無論記憶體夠不夠用,只要發生記憶體回收,弱引用都會被回收);

    4. 虛引用不會自動清除引用,當一個虛引用被認為是一定會被記憶體回收行程回收的時候,這個虛引用才會被註冊到引用隊列,而不會像軟引用和弱引用必須等到記憶體回收行程回收之後才會被註冊到引用隊列;


    解決:

    1. 驗證弱引用和軟引用的自動清除;

    2. 側面說明虛引用註冊時機——什麼是一定會被記憶體回收行程回收;


二、驗證準備1. 驗證方法介紹

    a. 選擇java.lang.ref.Reference中的方法isEnqueued來驗證當前引用是否已經進入引用隊列;清晰的邏輯還需要知道一個方法,即enqueue,這個方法會將當前引用放入隊列並修改當前引用的隊列為ReferenceQueueENQUEUED,整個原理很簡單,剩餘的代碼就不貼出來了。


    b. 當一個引用已經進入隊列,則可以用調用java.lang.ref.ReferenceQueue中的方法poll來將引用出隊列,特別注意的是,當一個引用出隊列的時候,他自身關聯的引用隊列會再一次被修改(上一次是進入隊列的時候),整個思想可以這麼來說,“不惹毛我的時候我們是朋友(引用和引用隊列是依賴關係),惹毛了我就搞你(進入隊列時候第一次被修改,引用不再依賴於引用隊列),搞完你了誰也不認識誰(出隊列的時候第二次修改)”,其實引用在出列的時候就沒有存在的必要了,但是引用隊列可能還被其他引用依賴,因此出隊列的引用要顯式的Reference=null。


2. 驗證類介紹

    準備一個類,不重寫finalize方法、重寫finalize方法、重寫的finalize方法產生this逃逸。

3. 知識鋪墊

    本文所涉及的關於記憶體回收的小知識補充。

    在《深入java虛擬機器(周志明著)》一書中垃圾收集演算法“可達性分析”(用來陳述什麼樣的對象會被記憶體回收),當一個對象被認為是不可達(可達、可恢複、不可達三種狀態)狀態時,該對象就會被記憶體回收。JVM判斷一個對象為不可達,一是該對象不存在強引用,二是是否有必要調用該對象的finalize方法(一個對象生命週期中只會被調用一次,千萬記住,該方法只會被調用一次),因為如果重寫了Object中的finalize方法,重寫邏輯中有可能會使得該對象變成可達狀態,那麼該對象將不會進行來及回收。

    是否有必要調用該對象的finalize方法,當該對象的類沒有重寫Object的finalize方法或該對象的finalize方法已經被調用過,則JVM認為不必調用,該對象會立即認為是不可達的;稍微複雜一點的情況是,一個對象的類重寫了Object的finalize方法且尚未被調用過,則該對象會被放入一個叫做F-QUEUE的低優先順序隊列中,等待被執行finalize方法,如果finalize方法被執行之後,該對象依舊不可達,則該對象進入不可達狀態,等待被記憶體回收,如果finalize方法被執行後該對象變為可達狀態(finalize方法this逸出問題),則該對象不會被記憶體回收,對象變為可達狀態。

    

三、PhantomReference1. 自動清除

    重不重寫finalize方法都可以,只要不發生finalize逃逸,則記憶體一定會被回收,但是千萬要注意的是,如果用String類來做驗證類,可能得不到你想要的結果,因為JVM內建字串池機制的存在會導致字串池強引用的存在,因此不會被記憶體回收,建議使用其他類做驗證類。

    String做測試和自訂類做測試的結果,如所示,String對象沒有被記憶體回收,因此不會被排入佇列。



2. 虛引用a. 不重寫finalize方法

    

2. 重寫finalize方法


3. 當finalize方法發生this逃逸


四、這才是虛引用    不像軟引用、弱引用會自動回收記憶體,虛引用的存在(雖然記憶體還是會被回收)更傾向於發送通知,當一個對象確定會被回收之後(此時虛引用中的引用對象並不能確定是否已經被回收記憶體了,而軟引用和弱引用一定是被回收記憶體了的),就會嚮應用程式發送一個通知(進入隊列和出隊列),“我要被清理了,你們是否要做些什麼事情呢?”。    所以,虛引用用來做對象清理工作,比finalize方法再好不過了,不會導致記憶體回收行程額外做工作,配合Reference阻塞方法remove就能更及時做清理工作。

著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

【J2SE】這才是java虛引用(PhantomReference)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.