我检查了LRUCache的官方Android文档,其中说:每次访问一个值时,它都会移动到队列的头部。将值添加到完整缓存时,该队列末尾的值将被逐出,并且可能符合垃圾回收的条件。 我想这是双链表,它由缓存使用的linkedhashmap维护。为了检查这种行为,我检查了LruCache的源代码,并检查了 get(K key)方法。它进一步调用map的get方法,该方法从底层hashmap获取值并调用recordAccess方法。
public V get(Object key) {
LinkedHashMapEntry<K,V> e = (LinkedHashMapEntry<K,V>)getEntry(key);
if (e == null)
return null;
e.recordAccess(this);
return e.value;
}
recordAccess方法依次将访问的条目移动到列表的末尾,以防accessOrder设置为true(对于我的问题,我们假设它是),否则它什么都不做。
/**
* This method is invoked by the superclass whenever the value
* of a pre-existing entry is read by Map.get or modified by Map.set.
* If the enclosing Map is access-ordered, it moves the entry
* to the end of the list; otherwise, it does nothing.
*/
void recordAccess(HashMap<K,V> m) {
LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;
if (lm.accessOrder) {
lm.modCount++;
remove();
addBefore(lm.header);
}
}
这听起来与上述声明相矛盾,因为它说元素被移动到队列的头部。相反,它移动到列表的最后一个元素(使用head.before)。当然,我在这里错过了什么,有什么帮助吗?
答案 0 :(得分:2)
您没有遗漏任何内容,只是您正在阅读LruCache
的{{1}}文档。 LinkedHashMap
有自己的文档,特别是有关accessOrder
的文档。 (在Java docs上相同)。
[...当accessOrder = true时...]迭代顺序是上次访问其条目的顺序,从最近访问到最近访问(访问顺序)
因此LinkedHashMap
将最近使用的条目放在最后,并记录在案。
实际上LinkedHashMap
描述了这种缓存在理论上是如何工作的,但是LruCache
显示了如何在不添加单独的向后移动迭代器的情况下实现它:通过将最近的元素放在最后,trimming可以使用已经可用的(向前移动的)迭代器来有效地访问(和移除)旧元素。
虽然在这里,现在我无法分辨removeEldestEntry
的错误。也许它在过去并不存在。
答案 1 :(得分:1)
来自LinkedHashMap
的javadoc:
如果使用了三个参数构造函数,并且 accessOrder 被指定为 true ,则迭代将按访问条目的顺序进行。访问顺序受 put , get 和 putAll 操作的影响,但不受集合视图上的操作影响。
Exactly the case,LruCache
有。
public LruCache(int maxSize) {
if (maxSize <= 0) {
throw new IllegalArgumentException("maxSize <= 0");
}
this.maxSize = maxSize;
this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
}
让我们看看recordAccess()
做了什么:
void recordAccess(HashMap<K,V> m) {
LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;
if (lm.accessOrder) { // true, because `LruCache` instantiated this
// map with `accessOrder = true`
lm.modCount++;
remove(); // remove this `LinkedHashMapEntry` from the map
addBefore(lm.header); // adds this entry before the current header of
// the map, thus this entry becomes the header
}
}
相反,它被移动到列表的最后一个元素(使用head.before)。
我看不出你的陈述是如何有效的。