2014-10-29 76 views
1

我在下面的遺留項目中看到LRU緩存的實現,其中我有一個關於使用SoftReference 作爲值對象而不是關鍵對象的問題。在Map中使用SoftReference?

下面是實現

public class LRUCacheImpl<K, V> implements LRUCache<K, V> { 

// SoftReference is used for a memory friendly cache. 
// The value will be removed under memory shortage situations and 
// the keys of the values will be removed from the cache map. 
private final Map<K, SoftReference<V>> cache; 


public LRUCacheImpl(final int cacheSize) { 

    // 'true' uses the access order instead of the insertion order. 
    this.cache = new LinkedHashMap<K, SoftReference<V>> (cacheSize, 0.75f, true) { 

    private static final long serialVersionUID = 1L; 

    @Override 
    protected boolean removeEldestEntry(Map.Entry<K, SoftReference<V>> eldest) { 
    // When to remove the eldest entry i.e. Least Recently Used (i.e. LRU) entry 
    return size() > cacheSize; // Size exceeded the max allowed. 
    } 
    }; 
} 

@Override 
public V put(K key, V value) { 
    SoftReference<V> previousValueReference = cache.put(key, new SoftReference<V>(value)); 
    return previousValueReference != null ? previousValueReference.get() : null; 
} 

@Override 
public V get(K key) { 
    SoftReference<V> valueReference = cache.get(key); 
    return valueReference != null ? valueReference.get() : null; 
} 
} 

GC回收了軟可及對象存儲應用程序是否即將達到內存不足(OOM)。 如果我應用相同的邏輯,則只應回收用於值的內存(因爲僅爲值對象創建軟參考)。
但這裏是我的問題是如何對應的密鑰對象將從地圖應用程序一次來到OOM中要刪除的文件

// SoftReference is used for a memory friendly cache. 
// The value will be removed under memory shortage situations and 
// the keys of the values will be removed from the cache map. 

開頭的註釋。不應該用軟參考包裝 ?

cache.put(new SoftReference<K>(key), new SoftReference<V>(value)); 
+0

'Key'預計將在尺寸較小的比較值,從而使按鍵軟裁判並沒有真正幫助不大 – 2014-10-29 07:14:18

+0

是您發佈的完整的類的代碼? 'removeEldestEntry'方法意味着此映射中鍵的數量應限制爲'cacheSize',但我沒有看到它在任何地方執行。 – Eran 2014-10-29 07:18:08

+0

@Eran這是完整的代碼。 removeEldestEntry被內部調用,同時把操作 – user3198603 2014-10-29 10:28:55

回答

2

我不知道LinkedHashMap支持限制地圖的大小。通過執行removeEldestEntry,可以防止地圖持有多於cacheSize密鑰。

正如您在LinkedHashMap實現中看到的那樣,如果removeEldestEntry返回true,那麼添加新條目會導致刪除最長條目。

void addEntry(int hash, K key, V value, int bucketIndex) { 
    createEntry(hash, key, value, bucketIndex); 

    // Remove eldest entry if instructed, else grow capacity if appropriate 
    Entry<K,V> eldest = header.after; 
    if (removeEldestEntry(eldest)) { 
     removeEntryForKey(eldest.key); 
    } else { 
     if (size >= threshold) 
      resize(2 * table.length); 
    } 
} 

因此,最近最少使用的鍵將從地圖中刪除。

使用此構造:

this.cache = new LinkedHashMap<K, SoftReference<V>> (cacheSize, 0.75f, true) 

意味着該條目是根據它們的訪問順序進行排序。因此,每次獲取或放入密鑰時,都會將相應的條目移動到列表鏈接列表的後面,這意味着列表的起始位置包含最近最少使用的條目。

因此,//the keys of the values will be removed from the cache map可能指的是最近最少使用的密鑰最終將從映射中移除,而與內存不足情況下值的移除無關。

+0

對於遲來的評論感到抱歉。但是我的問題在於'不應該用軟引用來包裝密鑰?'而不是僅僅在內存不足的情況下發生,這樣鍵和值都會被刪除? – user3198603 2015-12-24 04:46:55

0

Reference中的包裝密鑰是一個選項,如果錯綜複雜的話。
目標是避免OOM,同時不會產生任何缺點,無法從緩存中獲取值,以便不必要地釋放它們。
Reference堅稱我包裝密鑰是不夠標準的Map實現 -
沒有覆蓋equals() & hashCode(),無鑰匙會出現一樣的:沒有被發現,替換,刪除...
另一種方法是使用Soft/WeakReference s的Map.Entry s:請參見java.util.WeakHashMap<K, V>以瞭解如何操作的示例(順便提及參考關鍵字)。優點是,一旦你注意到軟/弱的引用消失,你可以擺脫任何剩餘的強引用。
然後,有trove4jApache Commons CollectionsGoldman Sachs ......