Android LruCache 原始碼分析

2021-07-26 05:44:19 字數 2756 閱讀 3799

學過作業系統這門課的朋友都還記得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是乙個抽象類,我們需要建立子...