LruCache源码分析

来源:互联网 发布:淘宝主播super米娜华少 编辑:程序博客网 时间:2024/06/01 10:10

1, 概念

Lru的全称是Least Recently Used,近期最少使用的; Cache是缓存的意思。

LruCache 的实现原理:把近期最少使用的数据从缓存中移除,保留使用最频繁的数据。LruCache 主要是利用LinkedHashMap这一数据结构来实现的。LruCache在android系统中应用广泛。

本文分析的LruCache路径:frameworks/base/core/java/android/util/LruCache.java

LruCache变量如下,

private final LinkedHashMap<K, V> map; //当前缓存的值private int size; // 元素个数private int maxSize; //最大值 private int putCount; //添加到缓存中的个数private int createCount; //创建的个数private int evictionCount; //被移除的个数private int hitCount; //正确获取个数private int missCount; //丢失个数

2, LruCache

首先看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);    }

WifiStateMachine中构造了一个大小为160的LruCache

private static final int SCAN_RESULT_CACHE_SIZE = 160;private final LruCache<NetworkDetail, ScanDetail> mScanResultCache;mScanResultCache = new LruCache<>(SCAN_RESULT_CACHE_SIZE);

2.1 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); // 其实加1            previous = map.put(key, value);            if (previous != null) { //在key值和哈希号相同的情况下才不为null,这时候只是替换                size -= safeSizeOf(key, previous);            }        }        if (previous != null) {            entryRemoved(false, key, previous, value); // 这个方法在此没有实际意义。        }        trimToSize(maxSize); // 调整结构        return previous;    }

添加元素主要分为2步骤,

1,调用map的put方法添加

2,调用trimToSize方法调整结构.

2.2 trimToSize方法

public 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) { // 如果size还未到阈值,就没必要调整                    break;                }                Map.Entry<K, V> 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);        }    }

主要三个步骤,

1,判断size是否到阈值,决定是否调整元素。

2,依次调用map 的eldest方法获取最不频繁的元素

  Map的内部是一个双向列表,所以直接返回链表最后一个元素就可以了,双向链表的效率高。如果是单向链表的话,还要一直查找到最后,效率很低。

Get方法就挺简单的。

3, 小结

1、LruCache 是基于 Lru算法实现的一种缓存机制;

2、Lru算法的原理是把近期最少使用的数据给移除掉,当然前提是当前数据的量大于设定的最大值。

3、LruCache 没有真正的释放内存,只是从 Map中移除掉数据,真正释放内存还是要用户手动释放。

0 0
原创粉丝点击