LruCache分析

LruCache:

LruCache是个泛型类,主要算法原理是把最近使用的对象用强引用(即我们平常使
用的对象引用方式)存储在 LinkedHashMap 中。当缓存满时,把最近最少使用的
对象从内存中移除,并提供了get和put方法来完成缓存的获取和添加操作。

强引用:直接对象的引用
弱引用:当一个对象只有一个弱引用存在时,此对象随时会被GC回收
软引用:当一个对象只有一个软引用存在时,当系统内存不足时,会被GC回收

LruCache使用:

 //获取系统内存
 int maxMemory = (int) (Runtime.getRuntime().totalMemory() / 1024);
       //设置缓存内存为系统内存的1/8
       int cacheSize=maxMemory/8;
        LruCache lruCache = new LruCache(cacheSize){
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return value.getRowBytes()*value.getHeight()/1024;
            }
        };

这段代码主要是确定LruCache的缓存大小,重写SizeOf是确定图片的大小。(单位要统一)

原理:

LruCache的核心就是维护一个缓存对象列表,其中列表对象的缓存排序为顺序排序,就是一直没访问的对象,将放在队尾,即将被淘汰。而最近访问的对象将放在队头,最后被淘汰。而这个队列是由LinkHashMap来维护的,它是一个数组+双向链表的数据结构来实现的。其中双向链表的结构可以实现访问顺序和插入顺序。这样的特性可以让LinkHashMap可以实现顺序排序。

分析LinkHashMap:看一下LinkHashMap的构造函数

 public LinkedHashMap(int initialCapacity,
                         float loadFactor,
                         boolean accessOrder) {
        super(initialCapacity, loadFactor);
        this.accessOrder = accessOrder;
        }

其中当参数 accessOrder=true,为排序,为false时为插叙。
那么LinkHaspMap,又是如何添加,获取还有删除的?
看下LruCache的put(添加):

 public final V put(K key, V value) {
 //判断键值对是否为空
        if (key == null || value == null) {
            throw new NullPointerException("key == null || value == null");
        }

        V previous;
        synchronized (this) {
            //添加就自增一次缓存对象数量
            putCount++;
            //增加缓存对象的大小
            size += safeSizeOf(key, value);
            //缓存对象
            previous = map.put(key, value);
            //如果已有相同的魂村对象,则恢复之前大小
            if (previous != null) {
                size -= safeSizeOf(key, previous);
            }
        }
        //空方法,一般用来做资源回收
        if (previous != null) {
            entryRemoved(false, key, previous, value);
        }
        //判断缓存是否满
        trimToSize(maxSize);
        return previous;
    }

看一下 trimToSize()方法:

  public void trimToSize(int maxSize) {
        while (true) {
            K key;
            V value;
            synchronized (this) {
    //如果map为空并且缓存size不等于0或者缓存size小于0,抛出异常
                if (size < 0 || (map.isEmpty() && size != 0)) {
                    throw new IllegalStateException(getClass().getName()
                            + ".sizeOf() is reporting inconsistent results!");
                }

                if (size <= maxSize) {
                    break;
                }
                //若如果超过缓存的操作
                Map.Entry toEvict = map.eldest();
                if (toEvict == null) {
                    break;
                }
            //获取最先访问的键值对,并且移除和回收资源
                key = toEvict.getKey();
                value = toEvict.getValue();
                map.remove(key);
                size -= safeSizeOf(key, value);
                evictionCount++;
            }
          //回收资源
            entryRemoved(true, key, value, null);
        }
    }

trimToSize()方法,就是一添加就会去循环判断缓存是否已满,不满则跳出循环,否则就删除最先访问的对象。
看一下get方法:

    public final V get(K key) {
    //判断
        if (key == null) {
            throw new NullPointerException("key == null");
        }

        V mapValue;
        synchronized (this) {
           //获取缓存对象,在get方法里面会把最近访问的放在头部
            mapValue = map.get(key);
            if (mapValue != null) {
                hitCount++;
                return mapValue;
            }
            missCount++;
        }

点进去get();

public V get(Object key) {
        Node e;
        if ((e = getNode(hash(key), key)) == null)
            return null;
            //排序
        if (accessOrder)
            afterNodeAccess(e);
        return e.value;
    }

由此可见LruCache中维护了一个集合LinkedHashMap,该LinkedHashMap是以
访问顺序排序的。当调用put()方法时,就会在结合中添加元素,并调用
trimToSize()判断缓存是否已满,如果满了就用LinkedHashMap的迭代器删除队尾
元素,即近期最少访问的元素。当调用get()方法访问缓存对象时,就会调用
LinkedHashMap的get()方法获得对应集合元素,同时会更新该元素到队头。

你可能感兴趣的:(LruCache分析)