美文网首页
LruCache原理解析--基于Android api28

LruCache原理解析--基于Android api28

作者: 郑土强ztq | 来源:发表于2020-02-27 21:20 被阅读0次

    简介

    • key-value结构。

    • 一个持有有限数量元素强引用的缓存机制。

    • 每次访问元素之后把它移动到序列的头部。cache已满的时候添加元素,序列尾部的元素就会被删除(释放引用)并可被GC。这就是最近最少使用的特性。LruCache保留频繁使用的元素,淘汰非频繁使用的元素。

    • 如果被缓存的元素持有需要被显式释放的资源,那么覆写entryRemoved函数去实现,因为删除只是代表释放引用,保存的数据可能需要a.release()去进行自己的释放。

    • 如果有这样的需求:get的时候没有即使命中元素也希望有元素返回,那么可以覆写create函数实现。

    • cache的size默认是按照key-value的数量决定的。如果想要按照内存大小去决定size,可以通过覆写sizeOf函数去实现。例如缓存4MB内存的bitmap:

      int cacheSize = 4 * 1024 * 1024; // 4MiB
      LruCache<String, Bitmap> bitmapCache = new LruCache<String, Bitmap>(cacheSize) {
              protected int sizeOf(String key, Bitmap value) {
                 return value.getByteCount();
             }
         }}
      
    • 线程安全。

    • get的时候key不能为空,在put的时候key和value都不能为空。如果get,put或者remove返回空,那么很明显:该key不在缓存中。

    • LruCache中封装了LinkedHashMap,LruCache加上了控制缓存大小的逻辑,实际上是通过LinkedHashMap保存数据的。

    基本原理

    LruCache中有个LinkedHashMap类型的成员变量map,在LruCache的构造函数中将会初始化map变量。map=new LinkedHashMap(0,0.75f,true),实例化了一个以访问顺序来排序元素的LinkedHashMap对象。LruCache只是加上了控制缓存大小的逻辑,实际上数据是由LinkedHashMap保存的。

    最近最少使用的特性是如何实现的?

    由LinkedHashMap保证此特性,在实例化LinkedHashMap时指定accessOrder参数为true。调用LinkedHashMap的put或者get函数都会把该元素插入(或者移动)到序列的尾部。LruCache每次put的时候会检查当前的大小是否超过了限制,是的话就会调用trimToSize去把最近最少使用的元素淘汰掉。

    trimToSize(int maxSize)

    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!");
                    }
    
                    if (size <= maxSize) {//1.
                        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) {//2.
                        break;
                    }
    
                    key = toEvict.getKey();
                    value = toEvict.getValue();
                    map.remove(key);
                    size -= safeSizeOf(key, value);
                    evictionCount++;
                }
    
                entryRemoved(true, key, value, null);
            }
        }
    

    trimToSize是个死循环,以下两种情况会退出循环:

    1. 当前的容量size<maxSize;

    2. LruCache中没有元素。

    这个函数是实现LruCache元素数量限制的关键。它会把LinkedHashMap的尾部数据,即不“活跃”的数据,remove掉,从而来实现元素数量限制的特性。

    相关文章

      网友评论

          本文标题:LruCache原理解析--基于Android api28

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