LruCache源码分析

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值