Java 中的 Reference

來源:互聯網
上載者:User

  在 jdk 1.2 及其以後,引入了強引用、軟引用、弱引用、虛引用這四個概念。網上很多關於這四個概念的解釋,但大多是概念性的泛泛而談,今天我結合著程式碼分析了一下,首先我們先來看定義與大概解釋(參考型別在包 java.lang.ref 裡)。

  1、強引用(StrongReference)

    強引用不會被GC回收,並且在java.lang.ref裡也沒有實際的對應類型。舉個例子來說:
    Object obj = new Object();
    這裡的obj引用便是一個強引用,不會被GC回收。

  2、軟引用(SoftReference)

    軟引用在JVM報告記憶體不足的時候才會被GC回收,否則不會回收,正是由於這種特性軟引用在caching和pooling中用處廣泛。軟引用的用法:

    Object obj = new Object();    SoftReference<Object> softRef = new SoftReference(obj);    // 使用 softRef.get() 擷取軟引用所引用的對象    Object objg = softRef.get();

  3、弱引用(WeakReference)

    當GC一但發現了弱引用對象,將會釋放WeakReference所引用的對象。弱引用使用方法與軟引用類似,但回收策略不同。

  4、虛引用(PhantomReference)

    當GC一但發現了虛引用對象,將會將PhantomReference對象插入ReferenceQueue隊列,而此時PhantomReference所指向的對象並沒有被GC回收,而是要等到ReferenceQueue被你真正的處理後才會被回收。虛引用的用法:

Object obj = new Object();ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>();PhantomReference<Object> phanRef = new PhantomReference<Object>(obj, refQueue);// 調用phanRef.get()不管在什麼情況下會一直返回nullObject objg = phanRef.get();// 如果obj被置為null,當GC發現了虛引用,GC會將phanRef插入進我們之前建立時傳入的refQueue隊列// 注意,此時phanRef所引用的obj對象,並沒有被GC回收,在我們顯式地調用refQueue.poll返回phanRef之後// 當GC第二次發現虛引用,而此時JVM將phanRef插入到refQueue會插入失敗,此時GC才會對obj進行回收Reference<? extends Object> phanRefP = refQueue.poll();

看了簡單的定義之後,我們結合著代碼來測試一下,強引用就不用說了,軟引用的描述也很清楚,關鍵是 “弱引用” 與 “虛引用”。

弱引用

public static void main(String[] args) throws InterruptedException {Object obj = new Object();ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>();WeakReference<Object> weakRef = new WeakReference<Object>(obj, refQueue);System.out.println(weakRef.get());System.out.println(refQueue.poll());obj = null;System.gc();System.out.println(weakRef.get());System.out.println(refQueue.poll());}

由於System.gc()是告訴JVM這是一個執行GC的好時機,但具體執不執行由JVM決定,因此當JVM決定執行GC,得到的結果便是(事實上這段代碼一般都會執行GC):

  java.lang.Object@de6ced
  null
  null
  java.lang.ref.WeakReference@1fb8ee3

從執行結果得知,通過調用weakRef.get()我們得到了obj對象,由於沒有執行GC,因此refQueue.poll()返回的null,當我們把obj = null;此時沒有引用指向堆中的obj對象了,這裡JVM執行了一次GC,我們通過weakRef.get()發現返回了null,而refQueue.poll()返回了WeakReference對象,因此JVM在對obj進行了回收之後,才將weakRef插入到refQueue隊列中。

虛引用

public static void main(String[] args) throws InterruptedException {Object obj = new Object();ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>();PhantomReference<Object> phanRef = new PhantomReference<Object>(obj, refQueue);System.out.println(phanRef.get());System.out.println(refQueue.poll());obj = null;System.gc();System.out.println(phanRef.get());System.out.println(refQueue.poll());}

同樣,當JVM執行了GC,得到的結果便是:

  null
  null
  null
  java.lang.ref.PhantomReference@1fb8ee3

從執行結果得知,我們先前說的沒有錯,phanRef.get()不管在什麼情況下,都會返回null,而當JVM執行GC發現虛引用之後,JVM並沒有回收obj,而是將PhantomReference對象插入到對應的虛引用隊列refQueue中,當調用refQueue.poll()返回PhantomReference對象時,poll方法會先把PhantomReference的持有隊列queue(ReferenceQueue<? super T>)置為NULL,NULL對象繼承自ReferenceQueue,將enqueue(Reference paramReference)方法覆蓋為return false,而此時obj再次被GC發現時,JVM再將PhantomReference插入到NULL隊列中便會插入失敗返回false,此時GC便會回收obj。事實上通過這段代碼我們也的卻看不出來obj是否被回收,但通過 PhantomReference 的javadoc注釋中有一句是這樣寫的:

Once the garbage collector decides that an object obj is phantom-reachable, it is being enqueued on the corresponding queue, but its referent is not cleared. That is, the reference queue of the phantom reference must explicitly be processed by some application code.

翻譯一下(這句話很簡單,我相信很多人應該也看得懂):

一旦GC決定一個“obj”是虛可達的,它(指PhantomReference)將會被入隊到對應的隊列,但是它的指代並沒有被清除。也就是說,虛引用的引用隊列一定要明確地被一些應用程式代碼所處理。

弱引用與虛引用的用處

  軟引用很明顯可以用來製作caching和pooling,而弱引用與虛引用呢?其實用處也很大,首先我們來看看弱引用,舉個例子:

 class Registry {     private Set registeredObjects = new HashSet();     public void register(Object object) {         registeredObjects.add( object );     } }

所有我添加進 registeredObjects 中的object永遠不會被GC回收,因為這裡有個強引用儲存在registeredObjects裡,另一方面如果我把代碼改為如下:

class Registry {     private Set registeredObjects = new HashSet();     public void register(Object object) {         registeredObjects.add( new WeakReference(object) );     } }

  現在如果GC想要回收registeredObjects中的object,便能夠實現了,同樣在使用HashMap如果想實現如上的效果,一種更好的實現是使用WeakHashMap。

而虛引用呢?我們先來看看javadoc的部分說明:

Phantom references are useful for implementing cleanup operations that are necessary before an object gets garbage-collected. They are sometimes more flexible than the finalize() method.

翻譯一下:

虛引用在實現一個對象被回收之前必須做清理操作是很有用的。有時候,他們比finalize()方法更靈活。

很明顯的,虛引用可以用來做對象被回收之前的清理工作。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.