Skip to main content
 首页 » 编程设计

java中map 中软引用的用法

2025年02月15日16wuhuacong

我在遗留项目中看到了下面的 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; 
 } 
} 

如果应用程序即将达到内存不足 (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,相应的关键对象将如何从 map 中删除。 key 不应该被包裹吗 也有软引用吗?

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

请您参考如下方法:

我不知道 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); 
    } 
} 

因此,最近最少使用的键将从 map 中删除。

使用此构造函数:

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

表示条目按照其访问顺序排序。因此,每次获取或放置一个键时,都会将相应的条目移动到列表链表的后面,这意味着列表的开头包含最近最少使用的条目。

因此,//这些值的键将从缓存映射中删除可能指的是最近最少使用的键最终将从映射中删除,与删除无关内存不足时的值。