2

我在一个遗留项目中看到了 LRU 缓存的下面实现,我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;
 }
}

如果应用程序即将达到 OutOfMemory(OOM),GC 会为可软访问对象回收内存。如果我应用相同的逻辑,则只应回收值的内存(因为仅为值对象创建软引用)。
但这是文件开头的注释

// 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.

我的问题是一旦应用程序到达 OOM,将如何从地图中删除相应的关键对象。密钥不应该也用软引用包装吗?

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

2 回答 2

2

我不知道LinkedHashMap支持限制地图大小的事实。通过实施removeEldestEntry,您可以防止地图包含多个cacheSize键。

正如您在实现中看到的那样,如果返回 true LinkedHashMap,则添加新条目会导致删除最旧的条目。removeEldestEntry

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可能是指最近最少使用的键最终将从映射中删除,与在内存不足的情况下删除值无关。

于 2014-10-29T11:00:47.357 回答
0

Reference如果复杂,将键包装在s 中是一种选择。
目标是避免 OOM,同时不会因没有从缓存中获取值而不必要地释放它们而产生任何缺点。
对于标准 Map 实现,仅将键包装在References 中是不够的 -
如果不覆盖equals()& hashCode(),则没有键看起来相等:没有找到、替换、删除...<br> 另一种方法是将Soft/WeakReferences 与 s 一起使用Map.Entry:请参阅java.util.WeakHashMap<K, V>示例如何做到这一点(顺便提一下钥匙)。优点是一旦发现软/弱引用消失了,您就可以摆脱任何剩余的强引用。
然后是trove4jApache Commons Collections高盛……</p>

于 2016-01-18T20:18:51.707 回答