8

I checked out official Android documentation for LRUCache which says : Each time a value is accessed, it is moved to the head of a queue. When a value is added to a full cache, the value at the end of that queue is evicted and may become eligible for garbage collection. I suppose this is the doubly linked list which is maintained by linkedhashmap which is used by the cache. To check this behavior, I checked out the source code for LruCache, and checked the get(K key) method. It further calls upon map's get method which gets the value from the underlying hashmap and calls upon recordAccess method.

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 method in turn moves the accessed entry to the end of the list in case accessOrder is set to true (for my problem let's assume it is), else it does nothing.

/**
     * 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);
        }
    }

This sounds contradictory to the above statement where it's said that the element is moved to the head of the queue. Instead it's moved to the last element of the list (using head.before). Surely, I'm missing something here, any help?

4

2 回答 2

2

您没有遗漏任何东西,只是您正在阅读LruCache. 有它自己的文档,特别是关于它的. (在Java 文档上也是如此)。LinkedHashMapLinkedHashMapaccessOrder

[...when accessOrder=true...] 迭代顺序是其条目最后一次访问的顺序,从最近最少访问到最近访问(访问顺序)

所以LinkedHashMap将最近使用的条目放在最后,并记录在案。

实际上LruCache描述了这种缓存在理论上是如何工作的,但LinkedHashMap展示了如何在不添加单独的向后移动迭代器的情况下实现它:通过将最近的元素放在最后,修剪可以使用已经可用的(向前移动的)迭代器来访问(和删除)旧元素有效。

虽然此时此地我不知道出了什么问题removeEldestEntry。也许它在过去并不存在。

于 2017-07-21T18:57:45.440 回答
1

来自的javadoc LinkedHashMap

如果使用三参数构造函数,并且accessOrder指定为true,则迭代将按照访问条目的顺序进行。访问顺序受putgetputAll操作影响,但不受集合视图上的操作影响。

确实如此,确实如此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)。

我看不出,你的陈述是如何有效的。

于 2017-07-15T13:41:16.117 回答