1. 程式人生 > >android中記憶體快取是如何實現的

android中記憶體快取是如何實現的

那就有必要來看看LruCache原始碼了
裡面有一個重要的資料結構LinkedHashMap。具體講解在這裡(http://blog.csdn.net/lxj1137800599/article/details/54974988
在此總結一下用法:
1.新增一個數據。先找到陣列中對應的index,然後把資料放到連結串列的最後位置。由於是雙向連結串列,那麼就等於放在header.prv
2.獲取一個數據。先找到陣列中對應的index,然後找到資料所在的位置。如果是按照讀取順序來排序的,那麼還要將這個節點放到雙向連結串列的最後一位(這個特性,可以實現LRU演算法)

public class LruCache<K, V> {
    //map用來儲存外界的快取物件
private final LinkedHashMap<K, V> map; // 建構函式 public LruCache(int maxSize) { if (maxSize <= 0) { throw new IllegalArgumentException("maxSize <= 0"); } this.maxSize = maxSize; //設定accessOrder為true,按照讀取順序來儲存快取 this.map = new LinkedHashMap<K, V>(0
, 0.75f, true); } //獲取一個快取物件 public final V get(K key) { if (key == null) { throw new NullPointerException("key == null"); } V mapValue; synchronized (this) { //設定為true了,還要將這個節點放到雙向連結串列的最後一位 mapValue = map.get(key); if
(mapValue != null) { hitCount++; return mapValue; } missCount++; } /* * Attempt to create a value. This may take a long time, and the map * may be different when create() returns. If a conflicting value was * added to the map while create() was working, we leave that value in * the map and release the created value. */ V createdValue = create(key); if (createdValue == null) { return null; } synchronized (this) { createCount++; //試著新增一個新值 //如果是要新增資料的,mapValue=null,size擴大然後trimToSize //如果是替換資料,mapValue!=null mapValue = map.put(key, createdValue); if (mapValue != null) { map.put(key, mapValue); } else { size += safeSizeOf(key, createdValue); } } if (mapValue != null) { entryRemoved(false, key, createdValue, mapValue); return mapValue; } else { trimToSize(maxSize); return createdValue; } } //新增一個快取物件 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); previous = map.put(key, value); // previous = null表示新新增的快取之前未存在過 // previous != null表示之前已存在資料 if (previous != null) { // 之前已有資料,那麼size再減回去 size -= safeSizeOf(key, previous); } } if (previous != null) { entryRemoved(false, key, previous, value); } trimToSize(maxSize); return previous; } //重點在這裡**************************************** //如果超出最大容量,那就去掉header.next //由於新新增的資料已經跑到header.prv去了,所以刪除的必定是最近最少使用的 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 || map.isEmpty()) { break; } Map.Entry<K, V> toEvict = map.entrySet().iterator().next(); key = toEvict.getKey(); value = toEvict.getValue(); map.remove(key); size -= safeSizeOf(key, value); evictionCount++; } entryRemoved(true, key, value, null); } } }

總結如下:accessOrder設定為true。
當新增快取時,先新增資料,再把對應的entry挪到雙向連結串列的末尾。如果size超過最大值,就刪除header.next
當獲取快取時,先獲取資料。由於設定為true,那麼也會將對應的entry挪到雙向連結串列的末尾