LruCache为什么要用LinkedHashMap?
来源:互联网 发布:项目评价软件 编辑:程序博客网 时间:2024/06/05 06:02
Android2.3以后弱引用、软引用和虚引用不再推荐使用, 但软引用还是有存在意义的, 详见软引用的黑科技 ; Google推荐使用LruCache类管理内存, 原理是Android dalvik和art虚拟机使用的是可达性分析方法,详见深入理解Java内存模型。
在LruCache类里保存对象引用, 当需要释放的时候删除该引用。LruCache类使用Least Recently Used即最近未使用的原则删除对象引用。 而LinkedHashMap保存了哈希表和双向链表的数据结构,该链表支持按访问次序排序, 所有LruCache类使用了LinkedHashMap。
一张草图说明LinkeHashMap的工作原理: 初始无数据、有1个数据,有2个数据,按照LRU算法删除数据;
初始无数据:
void init() { header = new LinkedHashMapEntry<>(-1, null, null, null); header.before = header.after = header; }header不保存真正数据, 只是充当索引的作用(即仅使用其before和after参数):
/** * The head of the doubly linked list. */ private transient LinkedHashMapEntry<K,V> header;
LinkedHashMap同时存在哈希表和双向链表的数据结构, 其成员变量header指向第一个LinkedHashMapEntry对象, 每个Entry都有before和after引用分别指向前一个和后一个Entry。
private static class LinkedHashMapEntry<K,V> extends HashMapEntry<K,V> { // These fields comprise the doubly linked list used for iteration. LinkedHashMapEntry<K,V> before, after;
从画的示意图可以看出header的before参数指向的就是最近使用的,即优先级最高; after参数指向的是最远被使用,即可能被释放的对象。 对于理解LinkedHashMap类工作原理, 搞明白header参数的befor和after代表的意义是基础。
在示意图中有元素1和元素2, 假定要根据LRU算法释放内存,就会删除元素1, 因为header的next指向它。 而删除动作就是取消元素1的指向和被指向, 元素1的引用计数为0,会被GC回收。
分析一下插入和读取的操作:
插入数据比HashMap增加了双向链表里添加数据的过程。
/**
* This override differs from addEntry in that it doesn't resize the
* table or remove the eldest entry.
*/
void createEntry(int hash, K key, V value, int bucketIndex) {
HashMapEntry<K,V> old = table[bucketIndex];
LinkedHashMapEntry<K,V> e = new LinkedHashMapEntry<>(hash, key, value, old);
table[bucketIndex] = e; //延续HashMap做法,即放在bucket的第一个位置
e.addBefore(header); //addBefore就是在链表末尾添加一个元素,并指向header且header指向该新元素
size++;
}
* Inserts this entry before the specified existing entry in the list.
*/
private void addBefore(LinkedHashMapEntry<K,V> existingEntry) {
after = existingEntry;
before = existingEntry.before;
before.after = this;
after.before = this;
}
读取:使用HashMap的get方法,时间复杂度一致; 只是增加了recordAccess过程, 即修改双向链表排序,使得header.before执行key对应的Entry。
public V get(Object key) {LinkedHashMapEntry<K,V> e = (LinkedHashMapEntry<K,V>)getEntry(key);
if (e == null)
return null;
e.recordAccess(this); //修改链表中key对应Entry的位置
return e.value;
}
总结: header.before是最新的Entry, header.after是最旧的; LinkedHashMap新增了双向链表的数据结构, 因为双向链表的读写时间复杂度是O(1), 所有LinkedHashMap的读写时间复杂度跟HashMap一样。
- LruCache为什么要用LinkedHashMap?
- LinkedHashMap 与 LRUcache
- LinkedHashMap与LRUCache实现
- LinkedHashMap最佳实践:LruCache
- 【转】LinkedHashMap 与 LRUcache
- java 基于linkedhashmap实现LRUCache
- Java-LinkedHashMap与LRUcache整理
- LinkedHashMap及LruCache是如何实现最少用最先淘汰算法
- LinkedHashMap 实现 LruCache 的底层数据结构?
- LruCache原理和用法与LinkedHashMap
- LRUCache原理及HashMap LinkedHashMap内部实现原理
- LRUCache
- LruCache
- LRUCache
- LruCache
- LRUCache
- LRUCache
- LruCache
- Handler、Looper消息队列模型,各部分的作用。
- 【POJ 2449】Remmarguts's Date (A*搜索第k短路)
- django路由系统之有名参数
- 常用Jackson注解解释
- rlwrap 友好支持sqlplus
- LruCache为什么要用LinkedHashMap?
- speex 回声消除(1)
- java 自 定 义 对 象 实 现 排 序
- Python爬取虎扑步行街,爆照区中的照片
- 整数中1出现的次数(从1到n整数中1出现的次数)
- Fedora25设置开机启动脚本
- python2 urllib2 重定向模拟学校图书馆用户登录(一)
- speex 回声消除(2)
- Android json数据中有转义字符