国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

全面解析Java中的GC與幽靈引用

2019-11-26 15:58:17
字體:
來源:轉載
供稿:網友

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

1、 Strong Reference
StrongReference 是 Java 的默認引用實現,  它會盡可能長時間的存活于 JVM 內, 當沒有任何對象指向它時 GC 執行后將會被回收

Java代碼

復制代碼 代碼如下:

@Test 
public void strongReference() { 
    Object referent = new Object(); 

    /**
     * 通過賦值創建 StrongReference 
     */ 
    Object strongReference = referent; 

    assertSame(referent, strongReference); 

    referent = null; 
    System.gc(); 

    /**
     * StrongReference 在 GC 后不會被回收
     */ 
    assertNotNull(strongReference); 


2、 WeakReference & WeakHashMap
WeakReference, 顧名思義,  是一個弱引用,  當所引用的對象在 JVM 內不再有強引用時, GC 后 weak reference 將會被自動回收
復制代碼 代碼如下:

@Test 
public void weakReference() { 
    Object referent = new Object(); 
    WeakReference<Object> weakRerference = new WeakReference<Object>(referent); 

    assertSame(referent, weakRerference.get()); 

    referent = null; 
    System.gc(); 

    /**
     * 一旦沒有指向 referent 的強引用, weak reference 在 GC 后會被自動回收
     */ 
    assertNull(weakRerference.get()); 


WeakHashMap 使用 WeakReference 作為 key, 一旦沒有指向 key 的強引用, WeakHashMap 在 GC 后將自動刪除相關的 entry
復制代碼 代碼如下:

@Test 
public void weakHashMap() throws InterruptedException { 
    Map<Object, Object> weakHashMap = new WeakHashMap<Object, Object>(); 
    Object key = new Object(); 
    Object value = new Object(); 
    weakHashMap.put(key, value); 

    assertTrue(weakHashMap.containsValue(value)); 

    key = null; 
    System.gc(); 

    /**
     * 等待無效 entries 進入 ReferenceQueue 以便下一次調用 getTable 時被清理
     */ 
    Thread.sleep(1000); 

    /**
     * 一旦沒有指向 key 的強引用, WeakHashMap 在 GC 后將自動刪除相關的 entry
     */ 
    assertFalse(weakHashMap.containsValue(value)); 


3、SoftReference
SoftReference 于 WeakReference 的特性基本一致, 最大的區別在于 SoftReference 會盡可能長的保留引用直到 JVM 內存不足時才會被回收(虛擬機保證), 這一特性使得 SoftReference 非常適合緩存應用
復制代碼 代碼如下:

@Test 
public void softReference() { 
    Object referent = new Object(); 
    SoftReference<Object> softRerference = new SoftReference<Object>(referent); 

    assertNotNull(softRerference.get()); 

    referent = null; 
    System.gc(); 

    /**
     *  soft references 只有在 jvm OutOfMemory 之前才會被回收, 所以它非常適合緩存應用
     */ 
    assertNotNull(softRerference.get()); 


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

Java代碼

復制代碼 代碼如下:

@Test 
public void phantomReferenceAlwaysNull() { 
    Object referent = new Object(); 
    PhantomReference<Object> phantomReference = new PhantomReference<Object>(referent, new ReferenceQueue<Object>()); 

    /**
     * phantom reference 的 get 方法永遠返回 null 
     */ 
    assertNull(phantomReference.get()); 


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

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

Java代碼

復制代碼 代碼如下:

@Test 
public void referenceQueue() throws InterruptedException { 
    Object referent = new Object();      
    ReferenceQueue<Object> referenceQueue = new ReferenceQueue<Object>(); 
    WeakReference<Object> weakReference = new WeakReference<Object>(referent, referenceQueue); 

    assertFalse(weakReference.isEnqueued()); 
    Reference<? extends Object> polled = referenceQueue.poll(); 
    assertNull(polled); 

    referent = null; 
    System.gc(); 

    assertTrue(weakReference.isEnqueued()); 
    Reference<? extends Object> removed = referenceQueue.remove(); 
    assertNotNull(removed); 


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、 對比

Soft vs Weak vs Phantom References
TypePurposeUseWhen GCedImplementing Class
Strong ReferenceAn ordinary reference. Keeps objects alive as long as they are referenced.normal reference.Any object not pointed to can be reclaimed.default
Soft ReferenceKeeps 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 ReferenceKeeps 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 reachablejava.lang.ref.WeakReference 
java.util.WeakHashMap
Phantom ReferenceLets you clean up after finalization but before the space is reclaimed (replaces or augments the use offinalize())Special clean up processingAfter finalization.java.lang.ref.PhantomReference

 

 

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

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 阿克陶县| 东港市| 伊宁市| 光泽县| 咸阳市| 康平县| 福贡县| 莱州市| 峨边| 阳春市| 拜泉县| 龙南县| 龙山县| 秦皇岛市| 阳山县| 扬中市| 南昌县| 应城市| 定州市| 抚顺市| 上虞市| 黄浦区| 房产| 龙南县| 望江县| 茶陵县| 资兴市| 柘荣县| 新龙县| 中宁县| 通榆县| 博罗县| 贡觉县| 申扎县| 太康县| 友谊县| 瑞丽市| 巨野县| 白沙| 宝山区| 津市市|