自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

簡(jiǎn)單理解Java GC與幽靈引用

開發(fā) 后端
Java中一共有4種類型的引用:StrongReference、SoftReference、WeakReference以及PhantomReference (幽靈引用), 這 4 種類型的引用與Java GC有著密切的關(guān)系, 讓我們逐一來(lái)看它們的定義和使用場(chǎng)景。

1. Strong Reference

StrongReference 是 Java 的默認(rèn)引用實(shí)現(xiàn),它會(huì)盡可能長(zhǎng)時(shí)間的存活于 JVM 內(nèi), 當(dāng)沒有任何對(duì)象指向它時(shí)Java GC 執(zhí)行后將會(huì)被回收

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

2. WeakReference & WeakHashMap

WeakReference, 顧名思義,是一個(gè)弱引用,當(dāng)所引用的對(duì)象在 JVM 內(nèi)不再有強(qiáng)引用時(shí), Java GC 后 weak reference 將會(huì)被自動(dòng)回收

  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 的強(qiáng)引用, weak reference 在 GC 后會(huì)被自動(dòng)回收  
  13.  */  
  14. assertNull(weakRerference.get());   
  15. }   
  16.  
  17.  @Test  
  18.  public void weakReference() {  
  19.   Object referent = new Object();  
  20.   WeakReference<Object> weakRerference = new WeakReference<Object>(referent);  
  21.    
  22.   assertSame(referent, weakRerference.get());  
  23.     
  24.   referent = null;  
  25.   System.gc();  
  26.     
  27.   /**  
  28.    * 一旦沒有指向 referent 的強(qiáng)引用, weak reference 在 GC 后會(huì)被自動(dòng)回收  
  29.    */  
  30.   assertNull(weakRerference.get());  
  31.  } 

WeakHashMap 使用 WeakReference 作為 key, 一旦沒有指向 key 的強(qiáng)引用, WeakHashMap 在Java GC 后將自動(dòng)刪除相關(guān)的 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.  * 等待無(wú)效 entries 進(jìn)入 ReferenceQueue 以便下一次調(diào)用 getTable 時(shí)被清理  
  15.  */  
  16. Thread.sleep(1000);   
  17.    
  18. /**  
  19.  * 一旦沒有指向 key 的強(qiáng)引用, WeakHashMap 在 GC 后將自動(dòng)刪除相關(guān)的 entry  
  20.  */  
  21. assertFalse(weakHashMap.containsValue(value));   
  22. }   
  23.  
  24.  @Test  
  25.  public void weakHashMap() throws InterruptedException {  
  26.   Map<Object, Object> weakHashMap = new WeakHashMap<Object, Object>();  
  27.   Object key = new Object();  
  28.   Object value = new Object();  
  29.   weakHashMap.put(key, value);  
  30.    
  31.   assertTrue(weakHashMap.containsValue(value));  
  32.     
  33.   key = null;  
  34.   System.gc();  
  35.     
  36.   /**  
  37.    * 等待無(wú)效 entries 進(jìn)入 ReferenceQueue 以便下一次調(diào)用 getTable 時(shí)被清理  
  38.    */  
  39.   Thread.sleep(1000);  
  40.     
  41.   /**  
  42.    * 一旦沒有指向 key 的強(qiáng)引用, WeakHashMap 在 GC 后將自動(dòng)刪除相關(guān)的 entry  
  43.    */  
  44.   assertFalse(weakHashMap.containsValue(value));  
  45.  } 

 3. SoftReference

SoftReference 于 WeakReference 的特性基本一致, ***的區(qū)別在于 SoftReference 會(huì)盡可能長(zhǎng)的保留引用直到 JVM 內(nèi)存不足時(shí)才會(huì)被回收(虛擬機(jī)保證), 這一特性使得 SoftReference 非常適合緩存應(yīng)用

  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 之前才會(huì)被回收, 所以它非常適合緩存應(yīng)用  
  13.  */  
  14. assertNotNull(softRerference.get());   
  15. }   
  16.  
  17.  @Test  
  18.  public void softReference() {  
  19.   Object referent = new Object();  
  20.   SoftReference<Object> softRerference = new SoftReference<Object>(referent);  
  21.    
  22.   assertNotNull(softRerference.get());  
  23.     
  24.   referent = null;  
  25.   System.gc();  
  26.     
  27.   /**  
  28.    *soft references 只有在 jvm OutOfMemory 之前才會(huì)被回收, 所以它非常適合緩存應(yīng)用  
  29.    */  
  30.   assertNotNull(softRerference.get());  
  31.  } 

4. PhantomReference

作為本文主角, Phantom Reference(幽靈引用) 與 WeakReference 和 SoftReference 有很大的不同,因?yàn)樗?get() 方法永遠(yuǎn)返回 null, 這也正是它名字的由來(lái)

  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 方法永遠(yuǎn)返回 null   
  8.  */  
  9. assertNull(phantomReference.get());   
  10. }   
  11.  
  12.  @Test  
  13.  public void phantomReferenceAlwaysNull() {  
  14.   Object referent = new Object();  
  15.   PhantomReference<Object> phantomReference = new PhantomReference<Object>(referent, new ReferenceQueue<Object>());  
  16.     
  17.   /**  
  18.    * phantom reference 的 get 方法永遠(yuǎn)返回 null   
  19.    */  
  20.   assertNull(phantomReference.get());  
  21.  } 

諸位可能要問(wèn), 一個(gè)永遠(yuǎn)返回 null 的 reference 要來(lái)何用,請(qǐng)注意構(gòu)造 PhantomReference 時(shí)的第二個(gè)參數(shù) ReferenceQueue(事實(shí)上 WeakReference & SoftReference 也可以有這個(gè)參數(shù)),
PhantomReference 唯一的用處就是跟蹤 referent何時(shí)被 enqueue 到 ReferenceQueue 中.

5. RererenceQueue

當(dāng)一個(gè) WeakReference 開始返回 null 時(shí), 它所指向的對(duì)象已經(jīng)準(zhǔn)備被回收, 這時(shí)可以做一些合適的清理工作. 將一個(gè) ReferenceQueue 傳給一個(gè) Reference 的構(gòu)造函數(shù), 當(dāng)對(duì)象被回收時(shí), 虛擬機(jī)會(huì)自動(dòng)將這個(gè)對(duì)象插入到 ReferenceQueue 中, WeakHashMap 就是利用 ReferenceQueue 來(lái)清除 key 已經(jīng)沒有強(qiáng)引用的 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. }  
  18.  
  19.  @Test  
  20.  public void referenceQueue() throws InterruptedException {  
  21.   Object referent = new Object();    
  22.   ReferenceQueue<Object> referenceQueue = new ReferenceQueue<Object>();  
  23.   WeakReference<Object> weakReference = new WeakReference<Object>(referent, referenceQueue);  
  24.     
  25.   assertFalse(weakReference.isEnqueued());  
  26.   Reference<? extends Object> polled = referenceQueue.poll();  
  27.   assertNull(polled);  
  28.     
  29.   referent = null;  
  30.   System.gc();  
  31.  
  32.   assertTrue(weakReference.isEnqueued());  
  33.   Reference<? extends Object> removed = referenceQueue.remove();  
  34.   assertNotNull(removed);  
  35.  } 


6.PhantomReferencevs WeakReference

PhantomReference有兩個(gè)好處, 其一, 它可以讓我們準(zhǔn)確地知道對(duì)象何時(shí)被從內(nèi)存中刪除, 這個(gè)特性可以被用于一些特殊的需求中(例如 Distributed GC,XWork 和 google-guice 中也使用 PhantomReference 做了一些清理性工作).

其二, 它可以避免 finalization 帶來(lái)的一些根本性問(wèn)題, 上文提到 PhantomReference 的唯一作用就是跟蹤 referent 何時(shí)被 enqueue 到 ReferenceQueue 中,但是 WeakReference 也有對(duì)應(yīng)的功能, 兩者的區(qū)別到底在哪呢 ?
這就要說(shuō)到 Object 的 finalize 方法, 此方法將在 gc 執(zhí)行前被調(diào)用, 如果某個(gè)對(duì)象重載了 finalize 方法并故意在方法內(nèi)創(chuàng)建本身的強(qiáng)引用,這將導(dǎo)致這一輪的 GC 無(wú)法回收這個(gè)對(duì)象并有可能
引起任意次 GC, ***的結(jié)果就是明明 JVM 內(nèi)有很多 Garbage 卻 OutOfMemory, 使用 PhantomReference 就可以避免這個(gè)問(wèn)題, 因?yàn)?PhantomReference 是在 finalize 方法執(zhí)行后回收的,也就意味著此時(shí)已經(jīng)不可能拿到原來(lái)的引用,也就不會(huì)出現(xiàn)上述問(wèn)題,當(dāng)然這是一個(gè)很極端的例子, 一般不會(huì)出現(xiàn).

7. 對(duì)比

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. Java GC小結(jié)
 一般的應(yīng)用程序不會(huì)涉及到 Reference 編程, 但是了解這些知識(shí)會(huì)對(duì)理解Java GC 的工作原理以及性能調(diào)優(yōu)有一定幫助, 在實(shí)現(xiàn)一些基礎(chǔ)性設(shè)施比如緩存時(shí)也可能會(huì)用到, 希望本文能有所幫助.

【編輯推薦】

  1. 成為Java高手的重要過(guò)程
  2. Java GUI的發(fā)展和演化簡(jiǎn)史
  3. Java正則表達(dá)式工具類實(shí)例
  4. 用Java壓縮文件解決沒有中文問(wèn)題示例
  5. Java與C++語(yǔ)言在作用域上的差異淺析
責(zé)任編輯:彭凡 來(lái)源: javaeye
相關(guān)推薦

2017-11-15 19:30:08

Python內(nèi)存泄露循環(huán)引用

2015-11-02 17:20:00

Java弱引用

2024-12-16 16:10:31

2021-01-21 14:06:57

云計(jì)算

2009-04-10 09:43:00

Java輸出流異常

2009-09-09 09:36:25

Linq對(duì)象引用

2023-12-25 09:30:41

Java垃圾回收

2019-11-27 14:41:50

Java技術(shù)語(yǔ)言

2019-09-16 09:23:34

高并發(fā)編程CountDownLaCyclicBarri

2013-08-19 17:14:04

.Net強(qiáng)引用弱引用

2013-07-31 09:03:45

2009-08-03 17:51:43

C#引用類型

2009-09-03 16:55:58

C#引用類型

2022-03-08 13:06:25

引用隊(duì)列jvm變量

2014-03-12 10:19:54

iOS對(duì)象

2009-08-17 14:48:44

Java參數(shù)傳遞機(jī)制

2012-05-25 09:40:07

2009-12-30 15:58:19

Silverlight

2015-05-14 15:38:40

javajava內(nèi)存泄露

2011-11-17 13:59:41

Java內(nèi)存管理內(nèi)存泄露
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)