理解 Java 的 GC 與 幽靈引用

來源:互聯網
上載者:User

理解 Java 的 GC 與 幽靈引用
 
         Java 中一共有 4 種類型的引用 : StrongReference、 SoftReference、 WeakReference 以及 PhantomReference (傳說中的幽靈引用 呵呵),
這 4 種類型的引用與 GC 有著密切的關係,  讓我們逐一來看它們的定義和使用情境 :

        1. Strong Reference
       
        StrongReference 是 Java 的預設引用實現,  它會儘可能長時間的存活於 JVM 內, 當沒有任何對象指向它時 GC 執行後將會被回收

 1 1.@Test  
2 2.public void strongReference() {
3 3. Object referent = new Object();
4 4.
5 5. /**
6 6. * 通過賦值建立 StrongReference
7 7. */
8 8. Object strongReference = referent;
9 9.
10 10. assertSame(referent, strongReference);
11 11.
12 12. referent = null;
13 13. System.gc();
14 14.
15 15. /**
16 16. * StrongReference 在 GC 後不會被回收
17 17. */
18 18. assertNotNull(strongReference);
19 19.}
20 @Test
21 public void strongReference() {
22 Object referent = new Object();
23
24 /**
25 * 通過賦值建立 StrongReference
26 */
27 Object strongReference = referent;
28
29 assertSame(referent, strongReference);
30
31 referent = null;
32 System.gc();
33
34 /**
35 * StrongReference 在 GC 後不會被回收
36 */
37 assertNotNull(strongReference);
38 }
39

 2. WeakReference & WeakHashMap

WeakReference, 顧名思義,  是一個弱引用,  當所引用的對象在 JVM 內不再有強引用時, GC 後 weak reference 將會被自動回收

1.@Test  
2.public void weakReference() {
3. Object referent = new Object();
4. WeakReference<Object> weakRerference = new WeakReference<Object>(referent);
5.
6. assertSame(referent, weakRerference.get());
7.
8. referent = null;
9. System.gc();
10.
11. /**
12. * 一旦沒有指向 referent 的強引用, weak reference 在 GC 後會被自動回收
13. */
14. assertNull(weakRerference.get());
15.}

WeakHashMap 使用 WeakReference 作為 key, 一旦沒有指向 key 的強引用, WeakHashMap 在 GC 後將自動刪除相關的 entry

1.@Test  
2.public void weakHashMap() throws InterruptedException {
3. Map<Object, Object> weakHashMap = new WeakHashMap<Object, Object>();
4. Object key = new Object();
5. Object value = new Object();
6. weakHashMap.put(key, value);
7.
8. assertTrue(weakHashMap.containsValue(value));
9.
10. key = null;
11. System.gc();
12.
13. /**
14. * 等待無效 entries 進入 ReferenceQueue 以便下一次調用 getTable 時被清理
15. */
16. Thread.sleep(1000);
17.
18. /**
19. * 一旦沒有指向 key 的強引用, WeakHashMap 在 GC 後將自動刪除相關的 entry
20. */
21. assertFalse(weakHashMap.containsValue(value));
22.}

3. SoftReference

SoftReference 於 WeakReference 的特性基本一致, 最大的區別在於 SoftReference 會儘可能長的保留引用直到 JVM 記憶體不足時才會被回收(虛擬機器保證), 這一特性使得 SoftReference 非常適合緩衝應用

1.@Test  
2.public void softReference() {
3. Object referent = new Object();
4. SoftReference<Object> softRerference = new SoftReference<Object>(referent);
5.
6. assertNotNull(softRerference.get());
7.
8. referent = null;
9. System.gc();
10.
11. /**
12. * soft references 只有在 jvm OutOfMemory 之前才會被回收, 所以它非常適合緩衝應用
13. */
14. assertNotNull(softRerference.get());
15.}

4. PhantomReference

        作為本文主角, Phantom Reference(幽靈引用) 與 WeakReference 和 SoftReference 有很大的不同,  因為它的 get() 方法永遠返回 null, 這也正是它名字的由來

1.@Test  
2.public void phantomReferenceAlwaysNull() {
3. Object referent = new Object();
4. PhantomReference<Object> phantomReference = new PhantomReference<Object>(referent, new ReferenceQueue<Object>());
5.
6. /**
7. * phantom reference 的 get 方法永遠返回 null
8. */
9. assertNull(phantomReference.get());
10.}

諸位可能要問, 一個永遠返回 null 的 reference 要來何用,  請注意構造 PhantomReference 時的第二個參數 ReferenceQueue(事實上 WeakReference & SoftReference 也可以有這個參數),
PhantomReference 唯一的用處就是跟蹤 referent  何時被 enqueue 到 ReferenceQueue 中.

     5. RererenceQueue

當一個 WeakReference 開始返回 null 時, 它所指向的對象已經準備被回收, 這時可以做一些合適的清理工作.   將一個 ReferenceQueue 傳給一個 Reference 的建構函式, 當對象被回收時, 虛擬機器會自動將這個對象插入到 ReferenceQueue 中, WeakHashMap 就是利用 ReferenceQueue 來清除 key 已經沒有強引用的 entries.

1.@Test  
2.public void referenceQueue() throws InterruptedException {
3. Object referent = new Object();
4. ReferenceQueue<Object> referenceQueue = new ReferenceQueue<Object>();
5. WeakReference<Object> weakReference = new WeakReference<Object>(referent, referenceQueue);
6.
7. assertFalse(weakReference.isEnqueued());
8. Reference<? extends Object> polled = referenceQueue.poll();
9. assertNull(polled);
10.
11. referent = null;
12. System.gc();
13.
14. assertTrue(weakReference.isEnqueued());
15. Reference<? extends Object> removed = referenceQueue.remove();
16. assertNotNull(removed);
17.}

6.  PhantomReference  vs WeakReference

PhantomReference  有兩個好處, 其一, 它可以讓我們準確地知道對象何時被從記憶體中刪除, 這個特性可以被用於一些特殊的需求中(例如 Distributed GC,  XWork 和 google-guice 中也使用 PhantomReference 做了一些清理性工作).

其二, 它可以避免 finalization 帶來的一些根本性問題, 上文提到 PhantomReference 的唯一作用就是跟蹤 referent 何時被 enqueue 到 ReferenceQueue 中,  但是 WeakReference 也有對應的功能, 兩者的區別到底在哪呢 ?
這就要說到 Object 的 finalize 方法, 此方法將在 gc 執行前被調用, 如果某個對象重載了 finalize 方法並故意在方法內建立本身的強引用,  這將導致這一輪的 GC 無法回收這個對象並有可能
引起任意次 GC, 最後的結果就是明明 JVM 內有很多 Garbage 卻 OutOfMemory, 使用 PhantomReference 就可以避免這個問題, 因為 PhantomReference 是在 finalize 方法執行後回收的,也就意味著此時已經不可能拿到原來的引用,  也就不會出現上述問題,  當然這是一個很極端的例子, 一般不會出現.

7. 對比

taken from http://mindprod.com/jgloss/phantom.html

 

Soft vs Weak vs Phantom References Type Purpose Use When GCed Implementing Class
Strong Reference An ordinary reference. Keeps objects alive as long as they are referenced. normal reference. Any object not pointed to can be reclaimed. default
Soft Reference Keeps objects alive provided there’s enough memory. to keep objects alive even after clients have removed their references (memory-sensitive caches), in case clients start asking for them again by key. After a first gc pass, the JVM decides it still needs to reclaim more space. java.lang.ref.SoftReference
Weak Reference Keeps objects alive only while they’re in use (reachable) by clients. Containers that automatically delete objects no longer in use. After gc determines the object is only weakly reachable java.lang.ref.WeakReference 
java.util.WeakHashMap
Phantom Reference Lets you clean up after finalization but before the space is reclaimed (replaces or augments the use offinalize()) Special clean up processing After finalization. java.lang.ref.PhantomReference

8. 小結
       一般的應用程式不會涉及到 Reference 編程, 但是瞭解這些知識會對理解 GC 的工作原理以及效能調優有一定協助,   在實現一些基礎性設施比如緩衝時也可能會用到, 希望本文能有所協助.

相關文章

聯繫我們

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