深入理解WeakHashmap

讀Hadoop源碼,遇到WeakHashMap,不明覺厲,趕緊百度一下,把百度到的結果收藏起來……

Tips:看完了才發現大多數講的是關於WeakReference的,和WeakHashMap基本上沒啥關係,屬於掛羊頭賣狗肉型的。不過,誰又說狗肉不好吃呢……尊重原著,就不改標題名了。

(一) 查看API文檔,WeakHashmap要點如下:

1. 以弱鍵實現的基於哈希表的 Map。在 WeakHashMap 中,當某個鍵不再正常使用時,將自動移除其條目。更精確地說,對於一個給定的鍵,其映射的存在並不阻止垃圾回收器對該鍵的丟棄,這就使該鍵成爲可終止的,被終止,然後被回收。丟棄某個鍵時,其條目從映射中有效地移除

2. WeakHashMap類的行爲部分取決於垃圾回收器的動作。因爲垃圾回收器在任何時候都可能丟棄鍵,WeakHashMap 就像是一個被悄悄移除條目的未知線程。特別地,即使對 WeakHashMap 實例進行同步,並且沒有調用任何賦值方法,在一段時間後 size 方法也可能返回較小的值,對於 isEmpty 方法,返回 false,然後返回true,對於給定的鍵,containsKey 方法返回 true 然後返回 false,對於給定的鍵,get 方法返回一個值,但接着返回 null,對於以前出現在映射中的鍵,put 方法返回 null,而 remove 方法返回 false,對於鍵 set、值 collection 和條目 set 進行的檢查,生成的元素數量越來越少。

3. WeakHashMap中的每個鍵對象間接地存儲爲一個弱引用的指示對象。因此,不管是在映射內還是在映射之外,只有在垃圾回收器清除某個鍵的弱引用之後,該鍵纔會自動移除。

(二) 引用對象的四種分類:

Api圖片如下:


1. 強引用(Strong Reference)

2. 弱引用(Weak Reference)

3. 軟引用(Soft Reference)

4. 幻象引用(Phantom Reference)

(三) 深入理解

至此,對於WeakHashMap有了一個基本概念,但是還是比較模糊。找到一篇英文文檔,將要點總結如下(如有翻譯不對,請指出,謝謝):

1. 強引用

強引用就是普通的Java引用,代碼:

StringBuffer buffer = new StringBuffer(); 

這句代碼創建了一個StringBuffer對象,在變量buffer中存儲了這個對象的一個強引用。強引用之所以稱之爲“強”(Strong),是因爲他們與垃圾回收器(garbage collector)交互的方式。特別是(specifically),如果一個對象通過強引用連接(strongly reachable-強引用可到達),那麼它就不在垃圾回收期處理之列。當你正在使用某個對象而不希望垃圾回收期銷燬這個對象時,強引用通常正好能滿足你所要的。

2. 當強引用太強的時候

假定你要使用一個final類Widget,但是基於某種原因,你不能繼承(extend)這個類或者通過其他方法爲這個類增加一些新的功能。如果你需要跟蹤(track)這個類的不同對象的序列號。那麼可以將這些對象放入HashMap中,獲得不同的value值,這樣就可以做到通過不同的value值跟蹤這些對象了。代碼: 

serialNumberMap.put(widget, widgetSerialNumber); 

但是widget的強引用會產生一些問題。在我們不需要一個Widget的序列號時,我們需要將這個Widget對應的Entry從HashMap中移除。否則我們可能面臨內存泄露(memory leak)的問題(如果我們沒有在應當移除Widgt的時候移除它),或者我們將莫名其妙的丟失序列號(如果我們正在使用Widget時卻移除了它)。如果這些問題類似,那麼這些問題是無垃圾回收機制(non-garbage-collected language)的編程語言的開發者所面臨的問題。Java的開發者不需要擔心這種問題。

W:如果一個對象具有強引用,那就類似於必不可少的生活用品,垃圾回收器絕不會回收它。當內存空 間不足,Java虛擬機寧願拋出OutOfMemoryError錯誤,使程序異常終止,也不會靠隨意回收具有強引用的對象來解決內存不足問題。

強引用的另外一個常見問題就是圖片緩存(cache)。普通的強引用將使得Image繼續保存在內存中。在一些情況下,我們不需要有些Image繼續留在內存中,我們需要將這些圖片從內存中移出,這時,我們將扮演垃圾回收期的角色來決定哪些照片被移除。使這些被移出的圖片被垃圾回收器銷燬。下一次,你被迫再次扮演垃圾回收期的角色,手動決定哪些Image被回收。

Note:我覺得也可以用對象的hashCode來跟蹤對象。作者在此所舉的例子,只在說明Strong Reference。

3. 弱引用


你可以使用weakWidget.get()方法老獲取實際的強引用對象。但是在之後,有可能突然返回null值(如果沒有其他的強引用在Widget之上),因爲這個弱引用被回收。其中包裝的Widget也被回收。

解決Widget序列號的問題,最簡單的方法就是使用WeakHashmap。其key值爲弱引用。如果一個WeakHashmap的key變成垃圾,那麼它對應用的value也自動的被移除。

W:垃圾回收期並不會總在第一次就找到弱引用,而是會找幾次才能找到。

4. 引用隊列(Reference Quene)

一旦弱引用返回null值,那麼其指向的對象(即Widget)就變成了垃圾,這個弱引用對象(即weakWidget)也就沒有用了。這通常意味着要進行一定方式的清理(cleanup)。例如,WeakHashmap將會移除一些死的(dread)的entry,避免持有過多死的弱引用。

ReferenceQuene能夠輕易的追蹤這些死掉的弱引用。可以將ReferenceQuene傳入WeakHashmap的構造方法(constructor)中,這樣,一旦這個弱引用指向的對象成爲垃圾,這個弱引用將加入ReferenceQuene中。

如下圖所示:


5. 軟引用

除了在拋出自己所指向的對象的迫切程度方面不一樣之外,軟引用和弱引用基本一樣。一個對象爲弱可到達(或者指向這個對象的強引用是一個弱引用對象-即強引用的弱引用封裝),這個對象將在一個垃圾回收循環內被丟棄。但是,弱引用對象會保留一段時間之後纔會被丟棄。

軟引用的執行和弱引用並沒有任何不同。但是,在供應充足(in plentiful supply)的情況下,軟可到達對象將在內存中保存儘可能長的時間。這使得他們在內存中有絕佳的存在基礎(即有儘可能長存在的基礎)。因爲你讓垃圾回收器去擔心兩件事情,一件是這個對象的可到達性,一件是垃圾回收期多麼想要這些對象正在消耗的內存。

6. 幻象引用(phantom reference)

幻象引用於弱引用和軟引用均不同。它控制其指向的對象非常弱(tenuous),以至於它不能獲得這個對象。get()方法通常情況下返回的是null值。它唯一的作用就是跟蹤列隊在ReferenceQuene中的已經死去的對象。

幻象引用和弱引用的不同在於其入隊(enquene)進入ReferenceQuene的方式。當弱引用的對象成爲若可到達時,弱引用即列隊進入ReferenceQuene。這個入隊發生在終結(finialize)和垃圾回收實際發生之前。理論上,通過不正規(unorthodox)的finilize()方法,成爲垃圾的對象能重新復活(resurrected),但是弱引用仍然是死的。幻象引用只有當對象在物理上從內存中移出時,纔會入隊。這就阻止我們重新恢復將死的對象。

W:終結(Finalization)指比拉圾回收更一般的概念,可以回收對象所佔有的任意資源,比如文件描述符和圖形上下文等。

幻象引用由兩個好處:

A:它能確定某一個對象從內存中移除的時間,這也是唯一的方式。通常情況下,這不是非常有用。但是遲早(come in handy)會用到手動處理大圖片的情況:如果你確定一張圖片需要被垃圾回收,那麼在你嘗試加載下一張照片前,你應該等待這張照片被回收完成。這樣就使得令人恐懼的(dreaded)內存溢出不太可能發生。

B:虛幻引用能夠避終結(finilize)的基本問題。finilize()方法能夠通過給一個垃圾對象關聯一個強引用使之復活。問題是覆寫了finilize()方法的對象在成爲垃圾之前,爲了回收,垃圾回收期需要執行兩次單獨的循環。第一輪循環確定某個對象是垃圾,那麼它就符合終結finilize的條件。在finilize的過程中,這個對象可能被“復活”。在這個對象被實際移除之前,垃圾回收期不得不重新運行一遍。因爲finilization並不是實時調用的,所以在終止進行的過程中,可能發生了gc的多次循環。在實際清理垃圾對象時,這導致了一些延時滯後。這將導致Heap中有大量的垃圾導致內存溢出。

幻象引用不可能發生以上的情況,當幻象引用入隊時,它實際上已經被移除了內存。幻象內存無法“復活”對象。這發現這個對象時虛幻可到達時,在第一輪循環中,它就被回收。

可以證明,finilize()方法從不在第一種情況下使用,但是虛幻引用提供了一種更安全和有效的使用和被排除掉的finilize方法的機制,使得垃圾回收更加簡單。但是因爲有太多的東西需要實現,我通常不適用finilize。

W:Object類中相關內容如下:

文檔中相關內容如下:


轉自:深入理解WeakHashmap


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章