2014-10-29 43 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 ......