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中移除掉数据,真正释放内存还是要用户手动释放。