美文网首页
Android-LruCache

Android-LruCache

作者: 有腹肌的豌豆Z | 来源:发表于2020-08-20 18:01 被阅读0次

LruCache介绍

  • LruCache 顾名思义就是使用LRU缓存策略的缓存,那么LRU是什么呢? 最近最少使用到的(least recently used),就是当超出缓存容量的时候,就优先淘汰链表中最近最少使用的那个数据。
  • 讲到LruCache,其实最关键的还是LinkedHashMap。LruCache的源码本身很少,而实现了LRU的功能都是靠LinkedHashMap。

首先看到构造方法:

 /**
     * @param maxSize for caches that do not override {@link #sizeOf}, this is
     *                the maximum number of entries in the cache. For all other caches,
     *                this is the maximum sum of the sizes of the entries in this cache.
     */
    public LruCache(int maxSize) {
        if (maxSize <= 0) {
            throw new IllegalArgumentException("maxSize <= 0");
        }
        // 最大缓存容量 
        this.maxSize = maxSize;
        // 创建一个LinkedHashMap,accessOrder 传true 按照访问顺序排序
        this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
    }

put 插入更新数据

/**
     * Caches {@code value} for {@code key}. The value is moved to the head of
     * the queue.
     *
     * @return the previous value mapped by {@code key}.
     */
    public final V put(K key, V value) {
        if (key == null || value == null) {
            throw new NullPointerException("key == null || value == null");
        }

        V previous; // 目标value 
        synchronized (this) {
            putCount++;
            // 计算value的大小 计算规则自己实现
            size += safeSizeOf(key, value);
            // 将value 保存到容器 
            previous = map.put(key, value);
            if (previous != null) {
                //如果之前存在,这先减去之前那个entry所占用的内存大小
                size -= safeSizeOf(key, previous);
            }
        }

        if (previous != null) {
            //如果之前存在则调用entryRemoved回调子类重写的此方法,做一些处理
            entryRemoved(false, key, previous, value);
        }

        //根据最大的容量,计算是否需要淘汰掉最不常使用的entry
        trimToSize(maxSize);
        return previous;
    }

淘汰策略trimToSize()

/**
     * @param maxSize the maximum size of the cache before returning. May be -1
     *                to evict even 0-sized elements.
     */
    private void trimToSize(int maxSize) {
        while (true) {
            K key;
            V value;
            synchronized (this) {
                if (size < 0 || (map.isEmpty() && size != 0)) {
                    throw new IllegalStateException(getClass().getName()
                            + ".sizeOf() is reporting inconsistent results!");
                }

                //如果当前已经使用的size小于最大容量,那就不做处理直接退出。
                if (size <= maxSize) {
                    break;
                }

                // BEGIN LAYOUTLIB CHANGE
                // get the last item in the linked list.
                // This is not efficient, the goal here is to minimize the changes
                // compared to the platform version.
                Map.Entry<K, V> toEvict = null;
                for (Map.Entry<K, V> entry : map.entrySet()) {
                    toEvict = entry;
                }
                // END LAYOUTLIB CHANGE

                if (toEvict == null) {
                    break;
                }

                key = toEvict.getKey();
                value = toEvict.getValue();
                //当超出容量的时候,通过map的iterator,获取第一个数据将其删除,一直循环,知道size小于maxsize为止。
                map.remove(key);
                size -= safeSizeOf(key, value);
                evictionCount++;
            }

            entryRemoved(true, key, value, null);
        }
    }
  • 从上面可以看到,trimSize就是LruCache控制内存大小,并且淘汰掉LRU策略中最不常使用的元素的地方。

get()

/**
     * Returns the value for {@code key} if it exists in the cache or can be
     * created by {@code #create}. If a value was returned, it is moved to the
     * head of the queue. This returns null if a value is not cached and cannot
     * be created.
     */
    public final V get(K key) {
        if (key == null) {
            throw new NullPointerException("key == null");
        }

        V mapValue;
        synchronized (this) {
            mapValue = map.get(key);
            if (mapValue != null) {
                hitCount++;
                return mapValue;
            }
            missCount++;
        }

        /*
         * Attempt to create a value. This may take a long time, and the map
         * may be different when create() returns. If a conflicting value was
         * added to the map while create() was working, we leave that value in
         * the map and release the created value.
         */

        V createdValue = create(key);
        if (createdValue == null) {
            return null;
        }

        synchronized (this) {
            createCount++;
            mapValue = map.put(key, createdValue);

            if (mapValue != null) {
                // There was a conflict so undo that last put
                map.put(key, mapValue);
            } else {
                size += safeSizeOf(key, createdValue);
            }
        }

        if (mapValue != null) {
            entryRemoved(false, key, createdValue, mapValue);
            return mapValue;
        } else {
            trimToSize(maxSize);
            return createdValue;
        }
    }

remove

/**
     * Removes the entry for {@code key} if it exists.
     *
     * @return the previous value mapped by {@code key}.
     */
    public final V remove(K key) {
        if (key == null) {
            throw new NullPointerException("key == null");
        }

        V previous;
        synchronized (this) {
            previous = map.remove(key);
            if (previous != null) {
                size -= safeSizeOf(key, previous);
            }
        }

        if (previous != null) {
            entryRemoved(false, key, previous, null);
        }

        return previous;
    }

相关文章

  • Android-LruCache

    LruCache,用于实现内存缓存,采用了Least Recently Used算法,即当缓存满时,优先删除最少使...

  • Android-LruCache

    LruCache介绍 LruCache 顾名思义就是使用LRU缓存策略的缓存,那么LRU是什么呢? 最近最少使用到...

网友评论

      本文标题:Android-LruCache

      本文链接:https://www.haomeiwen.com/subject/bljejktx.html