Android記憶體快取LruCache原始碼解析

2021-10-04 11:07:26 字數 2976 閱讀 8060

lrucache

lrucache是android提供的基於最近最少使用演算法的快取策略,該策略根據資料的歷史訪問記錄來進行淘汰資料,其核心思想是「如果資料最近被訪問過,那麼將來被訪問的機率也更高」。

lrucache的原理是在內部由linkedhashmap維護了乙個佇列,佇列按照訪問時間排序,head訪問時間最早,tail訪問時間最晚。當佇列長度超過設定的最大長度時,則從head開始挨個刪除,直到長度符合要求。

lrucache原始碼解析

從lrucache常用的幾個方法入手分析。

private final linkedhashmapmap;

/** size of this cache in units. not necessarily the number of elements. */

private int size;

private int maxsize;

public lrucache(int maxsize)

this.maxsize = maxsize;

this.map = new linkedhashmap(0, 0.75f, true);

}

lrucache的資料結構就是乙個linkedhashmap,在建構函式中初始化,並指定maxsize,maxsize指的是linkedhashmap中可以儲存的最大條數。

public final v put(k key, v value) 

v previous;

synchronized (this)

}if (previous != null)

trimtosize(maxsize); //將超出maxsize的資料移除

return previous;

}

put方法只是將資料put到linkedhashmap中,然後計算新的size值,並檢查是否超過maxsize,如果超過的話,將隊頭(最後訪問時間最早)的資料依次刪除。

public final v get(k key) 

v mapvalue;

synchronized (this)

misscount++;

}//map找不到的話,嘗試建立乙個,create預設返回null,所以一般情況下只執行到這裡就結束了。

v createdvalue = create(key);

if (createdvalue == null)

//如果createdvalue不為空的話,就put到linkedhashmap中,如果map中已經有值,就撤銷put操作

synchronized (this) else

}if (mapvalue != null) else

}

get方法先從linkedhashmap中獲取資料,如果存在值則返回。如果不存在值,則呼叫create方法,如果create方法沒有被重寫則返回null。如果被重寫了,會建立乙個createdvalue,並put到linkedhashmap中,如果與原有的值衝突了,就撤銷put操作,如果沒有衝突,就put到map中,並更新size。

看完lrucache的**,可以知道,快取數量超出限制之後,從隊頭挨個刪除。看起來平平無奇,那麼lrucache在**排序以實現lru的效果呢。這就需要看一下linkedhashmap了。

/**

* the head (eldest) of the doubly linked list.

*/transient linkedhashmapentryhead;

/*** the tail (youngest) of the doubly linked list.

*/transient linkedhashmapentrytail;

static class linkedhashmapentryextends hashmap.node

}

linkedhashmap是雙向鍊錶,head儲存的是最老的資料,而tail儲存的是最年輕的資料。

public v put(k key, v value) 

final v putval(int hash, k key, v value, boolean onlyifabsent,

boolean evict)

if (e.hash == hash &&

((k = e.key) == key || (key != null && key.equals(k))))

break;

p = e;}}

v oldvalue = e.value;

if (!onlyifabsent || oldvalue == null)

e.value = value;

afternodeaccess(e);

return oldvalue;}}

++modcount;

if (++size > threshold)

resize();

afternodeinsertion(evict);

return null;

}

從上面的**可以看出來,在put的時候,如果之前不存在當前key,則新增在隊尾。如果之前已經存在當前key,替換成新的value。然後會呼叫afternodeaccess。

void afternodeaccess(nodee) 

tail = p;

++modcount;

}}

在afternodeaccess中一頓鍊錶的操作,最後把p挪到了隊尾。因此,可以確定執行完put方法之後,新的value一定在隊尾。再回頭看get方法。

public v get(object key)
在get方法中同樣通過afternodeaccess方法將該node挪到隊尾。因此可以實現linkedhashmap按訪問時間進行排序。

Android記憶體優化之磁碟快取

基於以上的缺點有時候又須要第二種快取,那就是磁碟快取。大家應該都用過新聞client,非常多都有離線功能,功能的實現就是磁碟快取。在android中用到的磁碟快取大多都是基於disklrucache實現的,詳細怎麼使用呢?open 方法接收四個引數。第乙個引數是資料的快取檔案位址,第二個引數是當前應...

iOS快取 記憶體快取

為了減少與伺服器的連線溝通次數,提高應用程式的執行速度,使用了ios的快取機制 import youngviewcontroller.h inte ce youngviewcontroller end implementation youngviewcontroller void viewdidlo...

iOS快取 記憶體快取

為了減少與伺服器的連線溝通次數,提高應用程式的執行速度,使用了ios的快取機制 import youngviewcontroller.h inte ce youngviewcontroller end implementation youngviewcontroller void viewdidlo...