學過作業系統這門課的朋友都還記得lru
這個演算法吧,中文名叫」最近最久未使用」,它是用在頁面置換策略中的一種很巧妙的淘汰演算法,而在android
中,也有乙個快取淘汰機制用到了它,叫做lrucache
,它也可以說是乙個精妙的設計吧,這篇博文中,筆者將帶領大家剖析它原始碼中的精妙之處…
lrucache
類原始碼位於android.util.lrucache
包下,大家也可以同步閱讀。第一件事,便是看其實例化過程,只有乙個帶引數的建構函式,引數的意思是快取最大支援的記憶體容量,注意哦,不是數量,是占用空間的容量:
public
lrucache(int maxsize)
// 賦值
this.maxsize = maxsize;
// 建立 hashmap
// 引數:初始容量為0;載入因子為0.75;以最近最久未使用排序
this.map = new linkedhashmap(0, 0.75f, true);
}
它將最大容量賦給了成員變數,還建立了乙個linkedhashmap
,它是乙個迴圈鍊錶,前面兩個引數不要緊,關鍵在最後乙個引數,最後乙個引數含義是」是否以最近訪問的順序排序」,也就是說,如果為true
,那麼hashmap
的鍊錶將會以最近訪問的元素在尾部,很久沒訪問的元素在頭部的順序來排序,在linkedhashmap
的原始碼中可以證實這一說法:
// 呼叫此函式說明產生一次訪問記錄
public v get(object key)
}return
null;
}private
void
maketail(linkedentrye)
並且,通過linkedhashmap#eldest()
方法可以返回最老的結點:
public entryeldest()
初始化步驟為我們提供了乙個可供儲存快取的迴圈鍊錶,還提供好了lru
排序。接下來看看如何新增乙個快取記錄的:
public
final v put(k key, v value)
v previous;
synchronized (this)
}if (previous != null)
trimtosize(maxsize); // 重建大小 淘汰舊的元素
return previous;
}
不少的**,其實就是兩步,先將快取結點新增進linkedhashmap
,然後呼叫trimtosize(maxsize)
檢查大小並淘汰。接下來看看是如何淘汰就節點的:
public
void
trimtosize(int maxsize)
key = toevict.getkey();
value = toevict.getvalue();
map.remove(key); // 移除該元素
size -= safesizeof(key, value); // 減小大小
evictioncount++; // 移除的次數
}// 子類重寫方法以實現具體的移除策略
entryremoved(true, key, value, null);
}}
上面兩段**都提到了entryremoved()
方法,這其實是乙個供子類擴充套件功能的方法,它可以被子類覆寫,比如可以再增加一級磁碟快取,那麼磁碟上的新增和移除快取方法就需要子類來重寫了:
// 子類重寫方法 以實現具體的移除策略
// 引數一 表示 是否是被淘汰出去的
// 引數三 表示 移除了乙個舊的值 用新的值來替換
protected
void
entryremoved(boolean evicted, k key, v oldvalue, v newvalue) {}
// 子類重寫方法 以實現具體的新增策略
// 引數一 表示 鍵值對的鍵
protected v create(k key)
新增好了快取就可以取出來用了,接下來看是如何取出來的:
public
final v get(k key)
misscount++; // 沒有找到元素 丟失的快取數目
}// 如果快取容器中沒有值 就呼叫 create() 方法再建立
v createdvalue = create(key);
if (createdvalue == null)
synchronized (this) else
}if (mapvalue != null) else
}
其實完成的內容也很簡單,就是從linkedhashmap
中取出,如果有就返回,如果沒有就呼叫子類的create(key)
方法,最後要記得驗證是否需要淘汰最近最久未使用的元素。
lrucache
的原始碼還是很簡單的,但它很巧妙地結合linkedhashmap
實現了lru
演算法,可以說非常值得一讀!
Cartographer原始碼篇 原始碼分析 1
在安裝編譯cartographer 1.0.0的時候,我們可以看到 主要包括cartorgarpher ros cartographer ceres sover三個部分。其中,ceres solver用於非線性優化,求解最小二乘問題 cartographer ros為ros平台的封裝,獲取感測器資料...
AbstractListView原始碼分析3
normal list that does not indicate choices public static final int choice mode none 0 the list allows up to one choice public static final int choice ...
Android AsyncTask原始碼分析
android中只能在主線程中進行ui操作,如果是其它子執行緒,需要借助非同步訊息處理機制handler。除此之外,還有個非常方便的asynctask類,這個類內部封裝了handler和執行緒池。本文先簡要介紹asynctask的用法,然後分析具體實現。asynctask是乙個抽象類,我們需要建立子...