LRUCache 原理
目录
0、相关文章:
1、源码分析:
2、为什么用LinkedHashMap
0、相关文章:
LRUCache源码分析(自己的,很详细)
Glide--LruCache源码分析(文章一:阅读量152,1赞)
LruCache原理和用法与LinkedHashMap(文章二:阅读量6472,7赞)
java容器类LinkedHashMap源码分析
1、源码分析:
LruCache算法,又称为近期最少使用算法。主要算法原理就是把最近所使用的对象的强引用存储在LinkedHashMap上,并且,把最近最少使用的对象在缓存池达到预设值之前从内存中移除。
Glide中LruCache的源码:
public class LruCache<T, Y> {private final LinkedHashMap<T, Y> cache = new LinkedHashMap<>(100, 0.75f, true);private final int initialMaxSize;private int maxSize;private int currentSize = 0;/*** Constructor for LruCache.** @param size The maximum size of the cache, the units must match the units used in {@link* #getSize(Object)}.*/public LruCache(int size) {this.initialMaxSize = size;this.maxSize = size;}/*** Sets a size multiplier that will be applied to the size provided in the constructor to put the* new size of the cache. If the new size is less than the current size, entries will be evicted* until the current size is less than or equal to the new size.** @param multiplier The multiplier to apply.*/public synchronized void setSizeMultiplier(float multiplier) {if (multiplier < 0) {throw new IllegalArgumentException("Multiplier must be >= 0");}maxSize = Math.round(initialMaxSize * multiplier);evict();}/*** Returns the size of a given item, defaulting to one. The units must match those used in the* size passed in to the constructor. Subclasses can override this method to return sizes in* various units, usually bytes.** @param item The item to get the size of.*/protected int getSize(Y item) {return 1;}/*** A callback called whenever an item is evicted from the cache. Subclasses can override.** @param key The key of the evicted item.* @param item The evicted item.*/protected void onItemEvicted(T key, Y item) {// optional override}/*** Returns the current maximum size of the cache in bytes.*/public synchronized int getMaxSize() {return maxSize;}/*** Returns the sum of the sizes of all items in the cache.*/public synchronized int getCurrentSize() {return currentSize;}/*** Returns true if there is a value for the given key in the cache.** @param key The key to check.*/public synchronized boolean contains(T key) {return cache.containsKey(key);}/*** Returns the item in the cache for the given key or null if no such item exists.** @param key The key to check.*/@Nullablepublic synchronized Y get(T key) {return cache.get(key);}/*** Adds the given item to the cache with the given key and returns any previous entry for the* given key that may have already been in the cache.** <p> If the size of the item is larger than the total cache size, the item will not be added to* the cache and instead {@link #onItemEvicted(Object, Object)} will be called synchronously with* the given key and item. </p>** @param key The key to add the item at.* @param item The item to add.*/public synchronized Y put(T key, Y item) {final int itemSize = getSize(item);if (itemSize >= maxSize) {onItemEvicted(key, item);return null;}final Y result = cache.put(key, item);if (item != null) {currentSize += getSize(item);}if (result != null) {// TODO: should we call onItemEvicted here?currentSize -= getSize(result);}evict();return result;}/*** Removes the item at the given key and returns the removed item if present, and null otherwise.** @param key The key to remove the item at.*/@Nullablepublic synchronized Y remove(T key) {final Y value = cache.remove(key);if (value != null) {currentSize -= getSize(value);}return value;}/*** Clears all items in the cache.*/public void clearMemory() {trimToSize(0);}/*** Removes the least recently used items from the cache until the current size is less than the* given size.** @param size The size the cache should be less than.*/protected synchronized void trimToSize(int size) {Map.Entry<T, Y> last;while (currentSize > size) {last = cache.entrySet().iterator().next();final Y toRemove = last.getValue();currentSize -= getSize(toRemove);final T key = last.getKey();cache.remove(key);onItemEvicted(key, toRemove);}}private void evict() {trimToSize(maxSize);}
}
LruCache采用的集合是LinkedHashMap,这个集合是HashMap的基础上增加了 数据链表的功能,可以看到下面这个构造函数,第一个是初始容量100, 第二个是碰撞因子0.75(即真实容量到达总容量的75%就开始扩容),第三个是链表顺序是否按访问顺序,关于这个容器的代码分析我们放在下一篇文章,在这里我们只需要知道这个集合能记录到你访问数据的次序,最近的访问的会放在链表的前面
private final LinkedHashMap<T, Y> cache = new LinkedHashMap<>(100, 0.75f, true);
initialMaxSize:初始大小,maxSize:最大,currentSize:当前 三个成员变量,创建时this.initialMaxSize 和this.maxSize 一样。 注意setSizeMultiplier函数的作用是传入一个变化乘数,改变当前的最大容量
private final int initialMaxSize;private int maxSize;private int currentSize = 0;public LruCache(int size) {this.initialMaxSize = size;this.maxSize = size;}public synchronized void setSizeMultiplier(float multiplier) {if (multiplier < 0) {throw new IllegalArgumentException("Multiplier must be >= 0");}maxSize = Math.round(initialMaxSize * multiplier);evict();}
evict意思是驱逐,就是把数据清除出缓存,把容量缩减到小于等于maxSize,while循环,处理当前大小大于入参的情况,取出链表中的一个,获取其value的大小,清除,更新当前容器容量,直到符合要求
protected synchronized void trimToSize(int size) {Map.Entry<T, Y> last;while (currentSize > size) {last = cache.entrySet().iterator().next();final Y toRemove = last.getValue();currentSize -= getSize(toRemove);final T key = last.getKey();cache.remove(key);onItemEvicted(key, toRemove);}}private void evict() {trimToSize(maxSize);}
获取item的大小,默认现在是1 。比如要实现一个Bitmap 缓存是需要返回大小的,缓存的大小是取决于所有bitmap的总大小和,而不是总个数
protected int getSize(Y item) {return 1;
}
一个清除元素发生的回调,让LruCache 的继承者选择自己做要的事
protected void onItemEvicted(T key, Y item) {// optional override}
常规操作不解释
public synchronized int getMaxSize() {return maxSize;}public synchronized int getCurrentSize() {return currentSize;}public synchronized boolean contains(T key) {return cache.containsKey(key);}@Nullablepublic synchronized Y get(T key) {return cache.get(key);}
put操作,首先获取待加入的item 大小,如果大于缓存最大容量,就不放进去,直接调用onItemEvicte. 小于缓存最大容量,执行放入,item不为空,更新缓存当前大小。 执行放入的结果result就是说如果之前在容器内key存在,会执行替换value的操作,这时候result!=null,需要把替换出来的item的大小减去, 作者弄了个//TODO,不知道这里是否加上onItemEvicted 的回调,个人感觉应该加上,毕竟数据被清除缓存了,通知下,怎么处理交给继承者。 最后 evict(),因为单个待处理的item大小小于缓存最大容量,但是加入后,有可能超出,这里加个维护容量的代码
public synchronized Y put(T key, Y item) {final int itemSize = getSize(item);if (itemSize >= maxSize) {onItemEvicted(key, item);return null;}final Y result = cache.put(key, item);if (item != null) {currentSize += getSize(item);}if (result != null) {// TODO: should we call onItemEvicted here?currentSize -= getSize(result);}evict();return result;}
清除key出缓存,常规操作,维护当前缓存大小
public synchronized Y remove(T key) {final Y value = cache.remove(key);if (value != null) {currentSize -= getSize(value);}return value;}
让缓存容量小于等于0,起到clearMemory的作用
public void clearMemory() {trimToSize(0);}
2、为什么用LinkedHashMap
LRUCache源码分析(自己的,很详细)
为什么要用LinkedHashMap来存缓存呢,这个跟算法有关,LinkedHashMap刚好能提供LRUCache需要的算法。
这个集合内部本来就有个排序功能,当第三个参数是true的时候,数据在被访问的时候就会排序,这个排序的结果就是把最近访问的数据放到集合的最后面。
到时候删除的时候就从前面开始删除。
LRUCache 原理相关推荐
- LruCache原理
创建LruCache对象,重写其中的sizeOf方法: 然后看看LruCache内部长啥样子??? 看到A处,这里有个LinkedHashMap,这个是专门来存要缓存的对象,这个数据结构有个特点即链表 ...
- Android LRUCache原理
关于Android的三级缓存,其中主要的就是内存缓存和硬盘缓存.这两种缓存机制的实现都应用到了LruCache算法,今天我们就从使用到源码解析,来彻底理解Android中的缓存机制. 一.Androi ...
- Android基础-LruCache原理解析
一.Android中的缓存策略 一般来说,缓存策略主要包含缓存的添加.获取和删除这三类操作.如何添加和获取缓存这个比较好理解,那么为什么还要删除缓存呢?这是因为不管是内存缓存还是硬盘缓存,它们的缓存大 ...
- 浅析LruCache原理
Android用LruCache来取代原来强引用和软引用实现内存缓存,因为据说自2.3以后Android将更频繁的调用GC,导致软引用缓存的数据极易被释放. LruCache使用一个LinkedHas ...
- java lrucache_Java LruCache 的使用及原理
概述 LRU (Least Recently Used) 的意思就是近期最少使用算法,它的核心思想就是会优先淘汰那些近期最少使用的缓存对象. 在我们日常开发中,UI 界面进行网络图片加载是很正常的一件 ...
- Android开源框架源码鉴赏:LruCache与DiskLruCache
关于作者 郭孝星,程序员,吉他手,主要从事Android平台基础架构方面的工作,欢迎交流技术方面的问题,可以去我的Github提issue或者发邮件至guoxiaoxingse@163.com与我交流 ...
- Android性能优化之启动优化实战篇,最新整理
一.java面试题 熟练掌握java是很关键的,大公司不仅仅要求你会使用几个api,更多的是要你熟悉源码实现原理,甚至要你知道有哪些不足,怎么改进,还有一些java有关的一些算法,设计模式等等. (一 ...
- Android工程师面试该怎么准备?终局之战
(一)简介 Handler机制是一套Android消息传递机制.在Android开发多线程的应用场景中,将工作线程中需更新UI的操作信息 传递到 UI主线程,从而实现 工作线程对UI的更新处理,最终实 ...
- 深入理解JVM文章合集
原文地址:http://ddrv.cn/a/88331 Java动态追踪技术探究 在Java虚拟机中,字符串常量到底存放在哪 一次生产 CPU 100% 排查优化实践 聊聊 Java 虚拟机:类的加载 ...
最新文章
- NYOJ——街区最短路径问题
- china-pub计算机图书最新一周排行榜
- python项目2019_2019 年 11 月精选 GitHub 上 几个牛逼 Python 的项目
- 数据结构-单循环链表(C语言代码)
- JVM 调优实战--一个案例理解常用工具(命令)
- Spark 运行机制
- 基于matlab的频域辨识,基于Lab VIEW的控制系统频域分析研究
- 一个函数里两个setjmp_C语言中setjmp.h的longjmp()函数
- jmeter web监听结果_jmeter使用总结
- GBK转unicode码查询表
- Processing-基础小坑-
- java 关键字小结
- 移动端关于手机横屏时样式修改
- marlin 多轴电机驱动
- 洛谷P4234 最小差值生成树 题解
- 记录学习Android基础的心得07:硬件控制P2
- 视频去水印在线网站?
- java中的标号:outer的作用
- 很多男性的瘦腰细腿比女性更骨感?原因告诉你,或许他们真没减肥
- Jenkins凭据导出