LruCache源码分析

LRU(Least Recently Used)是一种很常用的资源调度策略,与20/80原则契合,在资源达到上限时倾向保留最近经常访问的资源对象。

Android中基于LRU实现了缓存对象,即LruCache,有两处实现:分别为android.support.v4.util.LruCache和android.util.LruCache,其中前者的设计符合Lru,

后者在资源不足时清除的最近经常访问的资源对象,使用时,需要注意这点,此处分析android.support.v4.util.LruCache的源码。

LruCache是一个范型类,其类图如下:

                          

可以看出LruCache是基于LinkedHashMap的,LinkedHashMap不是线程安全的,所以LruCache通过monitor方式,api上(内)对LruCahce对象

增加synchronized锁实现LruCache的线程安全。LruCache构造函数如下:
                
     
其中0.75表示LinkedHashMap内部的table使用率>=75%时,需要增加table大小,这样hash表的分布会更加均匀,避免向纯链表退化。

其中accessOrder非常重要,若为true,则链表的head->tail的顺序为"最近最少访问->最近经常访问",即当访问某个对象时,会将其插入到tail后,

作为新tail,若accessOrder为false,则在访问时不会移动访问对象的位置。accessOrder=true才符号LruCache的设计要求。

LruCache中的size含义很灵活,LruCache使用者可根据业务需求来定义,比如创建的是一个Bitmap缓存,如LruCache<String, Bitmap>,

这个size可以表示缓存中Bitmap的总大小(单位kb),LruCache提供了计算size的函数,调用者可在LruCache子类中重写来定义,但是需要保持其含义(单位)与

maxSize一致,比如:

下面简要分析下LruCache.get和put,其中get和put都在内部使用map时上锁,get核心代码如下: 

 可以看到, LruCache是不允许key为null的,当存在key对应的value时,直接返回,此处LinkedHashMap.get操作

会将value挪到tail上,实现如下:

可以看到LinkedHashMap是一个双向循环链表,再来看看put操作:

trimToSize的核心实现如下:

可以看到清理的是head指向的item,即最近最少使用的item,而android.util.LruCache的trimToSize清理的是tail:

 

总结如下:
1. LRU是一种资源调度策略,倾向清理最近最少访问的资源对象

2.Android中存在两个LruCache,使用support-v4包里的

3.LruCache基于LinkedHashMap的线程安全类,通过锁实现,最近访问的资源对象放到tail是通过LinkedHashMap.get实现

,资源回收是在put中实现。

4.LruCache子类一般需要重写sizeOf,定义缓存中的size 

posted on 2015-08-15 22:41  熊猫观星  阅读(708)  评论(3编辑  收藏  举报

导航