2012-02-06 61 views
7

Javadocs說:「當一個密鑰被丟棄時,它的輸入是有效的從地圖上移除」。WeakHashMap和強烈參考值

但是,除非有另一個線程偶爾刪除這樣的Map.Entry條目,那麼value對象是否不會被映射強引用?但是由於沒有這樣的線程在運行,只有get方法調用可以刪除這些條目 - 一次一個。

因爲這個原因,我幾乎總是使用WeakHashMap<K, WeakReference<V>>。爲什麼他們不會將默認行爲 - 值作爲弱引用呢?

+0

http://stackoverflow.com/questions/2473410/question-about-weakhashmap是一個幾乎相同的問題。但是我想知道我的斷言是否正確:只有當get()發現密鑰已被gc'ed時纔會刪除一個條目,除非我使用WeakReferences作爲值,否則坦白地說它並不具有很大的價值。 – 2012-02-06 20:16:58

+0

是的,它只是輪詢。如果你想要不同的東西,寫你自己的版本。 – 2012-02-06 20:21:56

+2

如果您需要不同的東西,請使用圖書館 - 編寫您自己的圖書非常棘手。番石榴有'MapMaker',它可以讓你配置關鍵和價值參考的實力:http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/MapMaker。 html – 2012-02-06 21:28:48

回答

8

引用隊列用於自動刪除條目。

http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/ref/ReferenceQueue.html

引用隊列中,向其中註冊的引用對象被垃圾收集器所附被檢測到適當的可到達性更改後。

基本上,弱引用是垃圾回收器的核心部分,所以當GC掃發生,未使用的引用被發現並投入到隊列,然後可以根據這些隊列的內容採取行動。

一個線程可以坐在隊列的remove方法中,當需要清理時需要提醒或poll隊列。

"Java theory and practice: Plugging memory leaks with weak references"解釋說:

WeakHashMap實施說明用弱引用一個常見的成語 - 一些內部對象擴展WeakReference

...

WeakHashMap使用弱引用的拿着地圖鍵,它允許垃圾回收的主要對象,當他們不再使用的應用程序和get()實施可以告訴從現場製圖是否WeakReference.get()返回null死一個。但這僅僅是保持Map的內存消耗在整個應用程序的整個生命週期內不斷增加的一半。在收集關鍵對象之後,還必須做一些修剪來自Map的死條目。 否則,地圖只會填滿與死鍵相對應的條目。雖然這對應用程序來說是不可見的,但它仍然可能導致應用程序內存不足,因爲即使密鑰是,也不會收集Map.Entry和值對象。

...

引用隊列是垃圾收集器的信息反饋至約對象的生命週期的應用程序的主要手段。弱引用有兩個構造函數:一個只將參照物作爲參數,另一個參照隊列。當一個弱引用已經創建了一個關聯的引用隊列並且所引用的對象成爲GC的候選對象之後,在引用被清除後,引用對象(而不是引用對象)將被引用到引用隊列中。然後,應用程序可以從參考隊列中檢索參考,並獲知參考物已被收集,以便它可以執行相關的清理活動,例如爲已經從弱集合中退出的對象刪除條目。 (引用隊列提供相同的出列模式作爲的BlockingQueue - 輪詢,定時阻擋,和無計時阻塞。)

編輯:

即使隊列,弱地圖仍可泄漏。 Ephemerons是一個試圖解決弱關鍵引用強關鍵值的情況。它們不能在java中實現。

Ephemerons解決了通過使用註冊表嘗試「附加」屬性到對象時常見的問題。當一些屬性應該附加到一個對象時,屬性應該(根據GC行爲)通常具有該對象的實例變量所具有的生命週期。

property --------- registry --------- association --------- object 

這裏,註冊表(第三方)將保留的關聯本身這將需要從註冊表手工清除(:然而,這是通過使對象及其屬性諸如之間的外部關聯複雜而不是自動垃圾收集)。儘管通過使用各種弱關聯類型之一,在任何給定的具體情況下都可以解決這個問題,但選擇「正確」的關聯類型取決於各種因素,其中一些因素可以動態變化。

Ephemerons通過定義一個ephemeron的'內容'(價值)將被強有力地保存直到該密鑰被稱爲垃圾收集來解決這個問題。從此,ephemeron的內容將保持微弱。因此,當且僅當密鑰是垃圾收集時,ephemeron的內容纔有資格進行垃圾收集,這是我們對於對象的實例變量所觀察到的確切行爲。

+0

忘記參考隊列調用我們自己的鉤子的能力。 – 2012-02-06 22:45:06

+0

我從你的鏈接中找到「WeakHashMap有一個叫做expungeStaleEntries()的私有方法,在大多數Map操作中被調用。」有用。並想知道是否產生一個實際上阻塞讀取參考隊列的線程可能是一個更好的主意。也許這就是Guava的MapMaker所做的。 – 2012-02-06 23:09:31

+1

@UstamanSangat,我不知道MapMaker做了什麼,但是可能expungeStaleEntries()輪詢參考隊列以使用地圖緩衝清理。我會嘗試使用MapMaker之類的東西,然後再實施我自己的關鍵清理。順便說一句,我添加了一個編輯,指出了即使使用弱關鍵映射也可能會泄漏內存的方式。 – 2012-02-06 23:21:22