在android中乙個應用程式占用的記憶體是有限的,而android中通常需要載入很多顯示給使用者,是很消耗記憶體的,稍微處理不好就很容易報oom異常。而且無論是從本地還是網路獲取,解析並載入進記憶體都是乙個耗時的過程,所以我們通常就會把一些常用的儲存在記憶體中,在使用的時候直接從記憶體中獲取,從而提高程式的響應性和使用者體驗。在儲存到記憶體中就會用到lrucache這個類,今天我們就看看這個類的簡單使用和內部實現原理。
// 以在記憶體中儲存為例:
int cachesize = (int) (runtime.getruntime().maxmemory()/8); // 獲取最大記憶體的1/8用來儲存
lrucachelrucache = new lrucache(cachesize)
};// 使用的時候直接呼叫put(string,bitmap),get(string)和remove(string)方法就可以直接存、取、移除物件了。它會在每次存入物件的時候,自動檢測是否超過設定的總記憶體大小,如果沒有,就直接存入,如果超過設定的最大記憶體,就會移除掉最先存入最不常用的物件。
構造方法
public
lrucache(int maxsize)
this.maxsize = maxsize;
this.map = new linkedhashmap(0, 0.75f, true);
}//在建立lrucache物件的時候,在構造方法中會建立乙個初始容量為0,載入因子為0.75 ,順序訪問(呼叫get方法後,會將這次訪問的元素移至鍊錶尾部,不斷訪問可以形成按訪問順序排序的鍊錶)的linkedhashmap容器來保持物件,同時設定lrucache儲存的物件最大能夠占用的記憶體大小。
get方法
public final v get(k key)
v mapvalue;
synchronized (this)
misscount++;
}// 上面這段**,首先會根據傳入的key在linkedhashmap中去取對應的物件,如果返回的物件不為null,那麼就直接返回,否則就會走下面這段**呼叫create(string)方法獲取物件,在原始碼中該方法返回的是null,所以最終結果返回null,
v createdvalue = create(key);
if (createdvalue == null)
// 如果我們覆寫掉create方法,使其返回不為null,那麼就繼續走下面這段**,將建立的物件儲存在linkedhashmap中,在這裡就涉及到多執行緒問題,如果多執行緒操作時,在走到下面同步**塊之前,呼叫了put方法往linkedhashmap中存入了key對應的元素,那麼在這裡呼叫put方法後,返回的mapvalue就不為空,然後走if中的**,將put方法存入的物件重新存一邊,棄用create()方法獲取的物件,也就是說在這裡優先使用put方法存入的物件;然後再緊接著走下面同步**塊後面的if...else中if裡面的**,呼叫entryremoved()方法,然後返回;如果mapvalue仍然返回null,那麼就呼叫safesizeof()方法計算新增後map中物件佔總記憶體的大小,然後走同步**塊之後if..else中else中**,呼叫trimtosize()方法之後,返回
synchronized (this) else
}if (mapvalue != null) else
}//create方法
protected v create(k key)
//safesizeof方法
private
intsafesizeof(k key, v value)
return result;
}// entryremoved方法
protected
void
entryremoved(boolean evicted, k key, v oldvalue, v newvalue) {}
put方法
//呼叫put方法的時候,計算新增後記憶體中物件佔的空間總大小,在新增過程中如果之前存入過,釋放之前存入的物件,同時重新獲取釋放之後linkedhashmap中物件佔記憶體的大小,然後再每次新增需要判斷是否占有的總記憶體大小是否超過設定的記憶體大小,如果超過,會移除掉最早新增的元素。
public final v put(k key, v value)
v previous;
synchronized (this)
}if (previous != null)
trimtosize(maxsize); // 判斷是否超過設定的總大小,如果超過,移除最早新增最不常用的物件
return previous;
}
remove方法
public
final v remove(k key)
v previous;
synchronized (this)
}if (previous != null)
return previous;
}
trimtosize方法(重點)
//lrucache之所以能夠在儲存的物件占用的總空間超過設定的大小時,及時對最早最不常用的物件進行釋放,最主要的就是下面這段**。
public
void
trimtosize(int maxsize)
// 只有在linkedhashmap中物件總大小小於等於設定的最大值,或者linkedhashmap為空的時候,才會跳出迴圈,否則會每次都移除鍊錶頭部的元素,並進入下一次迴圈
if (size <= maxsize || map.isempty())
map.entrytoevict = map.entryset().iterator().next();
key = toevict.getkey();
value = toevict.getvalue();
map.remove(key);
size -= safesizeof(key, value);
evictioncount++;
}entryremoved(true, key, value, null);
}}
LruCache原始碼解析 快取策略分析
最近在學習glide原始碼用到了lrucache,lru least recently used 的意思就是近期最少使用演算法,它的核心思想就是會優先淘汰那些近期最少使用的快取物件。有序map,此處用到了基於訪問的排序 private final linkedhashmapmap 當前快取容量 pr...
Java簡單了解LruCache原始碼
1.在lrucache的構造器中很明顯知道lrucache使用linkedhashmap,並且將accessorder設定為true。這樣在使用linkedhashmap的get 方法的時候就會使其雙鏈表重新進行排序,也就是將當前查詢的節點斷開,然後呼叫addbefore 方法重新將節點新增到雙鏈表...
Fabric 原始碼解析 原始碼目錄解析
這裡對重要的一些目錄進行說明 bccsp 與密碼學 加密 簽名 證書等等 相關的加密服務 將fabric中用到的密碼學相關的函式抽象成了一組介面,便於拓展。bddtests 一種新型的軟體開發模式 行為驅動開 需求 開發 common 一些公共庫 錯誤處理 日誌處理 賬本儲存 策略以及各種工具等等 ...