LRu Cache演算法原理

2022-09-14 21:36:29 字數 2990 閱讀 2966

lru cache演算法原理:

1. 新資料插入到鍊錶頭部;

2. 每當快取命中(即快取資料被訪問),則將資料移到鍊錶頭部;

3. 當鍊表滿的時候,將鍊錶尾部的資料丟棄。

分析【命中率】

當存在熱點資料時,lru的效率很好,但偶發性的、週期性的批量操作會導致lru命中率急劇下降,快取汙染情況比較嚴重。

【複雜度】

實現簡單。

【代價】

命中時需要遍歷鍊錶,找到命中的資料塊索引,然後需要將資料移到頭部。

lru-k

2.1. 原理

lru-k中的k代表最近使用的次數,因此lru可以認為是lru-1。lru-k的主要目的是為了解決lru演算法「快取汙染」的問題,其核心思想是將「最近使用過1次」的判斷標準擴充套件為「最近使用過k次」。

2.2. 實現

相比lru,lru-k需要多維護乙個佇列,用於記錄所有快取資料被訪問的歷史。只有當資料的訪問次數達到k次的時候,才將資料放入快取。當需要淘汰資料時,lru-k會淘汰第k次訪問時間距當前時間最大的資料。詳細實現如下:

1. 資料第一次被訪問,加入到訪問歷史列表;

2. 如果資料在訪問歷史列表裡後沒有達到k次訪問,則按照一定規則(fifo,lru)淘汰;

3. 當訪問歷史佇列中的資料訪問次數達到k次後,將資料索引從歷史佇列刪除,將資料移到快取佇列中,並快取此資料,快取佇列重新按照時間排序;

4. 快取資料佇列中被再次訪問後,重新排序;

5. 需要淘汰資料時,淘汰快取佇列中排在末尾的資料,即:淘汰「倒數第k次訪問離現在最久」的資料。

lru-k具有lru的優點,同時能夠避免lru的缺點,實際應用中lru-2是綜合各種因素後最優的選擇,lru-3或者更大的k值命中率會高,但適應性差,需要大量的資料訪問才能將歷史訪問記錄清除掉。

two queues(2q)

3.1. 原理

two queues(以下使用2q代替)演算法類似於lru-2,不同點在於2q將lru-2演算法中的訪問歷史佇列(注意這不是快取資料的)改為乙個fifo快取佇列,即:2q演算法有兩個快取佇列,乙個是fifo佇列,乙個是lru佇列。

3.2. 實現

當資料第一次訪問時,2q演算法將資料快取在fifo佇列裡面,當資料第二次被訪問時,則將資料從fifo佇列移到lru佇列裡面,兩個佇列各自按照自己的方法淘汰資料。詳細實現如下:

1. 新訪問的資料插入到fifo佇列;

2. 如果資料在fifo佇列中一直沒有被再次訪問,則最終按照fifo規則淘汰;

3. 如果資料在fifo佇列中被再次訪問,則將資料移到lru佇列頭部;

4. 如果資料在lru佇列再次被訪問,則將資料移到lru佇列頭部;

5. lru佇列淘汰末尾的資料。

注:上圖中fifo佇列比lru佇列短,但並不代表這是演算法要求,實際應用中兩者比例沒有硬性規定。

3.3. 分析

【命中率】

2q演算法的命中率要高於lru。

【複雜度】

需要兩個佇列,但兩個佇列本身都比較簡單。

【代價】

fifo和lru的代價之和。

2q演算法和lru-2演算法命中率類似,記憶體消耗也比較接近,但對於最後快取的資料來說,2q會減少一次從原始儲存讀取資料或者計算資料的操作。

multi queue(mq)

4.1. 原理

mq演算法根據訪問頻率將資料劃分為多個佇列,不同的佇列具有不同的訪問優先順序,其核心思想是:優先快取訪問次數多的資料。

4.2. 實現

mq演算法將快取劃分為多個lru佇列,每個佇列對應不同的訪問優先順序。訪問優先順序是根據訪問次數計算出來的,例如

詳細的演算法結構圖如下,q0,q1....qk代表不同的優先順序佇列,q-history代表從快取中淘汰資料,但記錄了資料的索引和引用次數的佇列:

如上圖,演算法詳細描述如下:

1. 新插入的資料放入q0;

2. 每個佇列按照lru管理資料;

3. 當資料的訪問次數達到一定次數,需要提公升優先順序時,將資料從當前佇列刪除,加入到高一級佇列的頭部;

4. 為了防止高優先順序資料永遠不被淘汰,當資料在指定的時間裡訪問沒有被訪問時,需要降低優先順序,將資料從當前佇列刪除,加入到低一級的佇列頭部;

5. 需要淘汰資料時,從最低一級佇列開始按照lru淘汰;每個佇列淘汰資料時,將資料從快取中刪除,將資料索引加入q-history頭部;

6. 如果資料在q-history中被重新訪問,則重新計算其優先順序,移到目標佇列的頭部;

7. q-history按照lru淘汰資料的索引。

4.3. 分析

【命中率】

mq降低了「快取汙染」帶來的問題,命中率比lru要高。

【複雜度】

mq需要維護多個佇列,且需要維護每個資料的訪問時間,複雜度比lru高。

【代價】

mq需要記錄每個資料的訪問時間,需要定時掃瞄所有佇列,代價比lru要高。

注:雖然mq的佇列看起來數量比較多,但由於所有佇列之和受限於快取容量的大小,因此這裡多個佇列長度之和和乙個lru佇列是一樣的,因此佇列掃瞄效能也相近。

由於不同的訪問模型導致命中率變化較大,此處對比僅基於理論定性分析,不做定量分析。

對比點對比

命中率lru-2 > mq(2) > 2q > lru

複雜度lru-2 > mq(2) > 2q > lru

代價lru-2  > mq(2) > 2q > lru

實際應用中需要根據業務的需求和對資料的訪問情況進行選擇,並不是命中率越高越好。例如:雖然lru看起來命中率會低一些,且存在」快取汙染「的問題,但由於其簡單和代價小,實際應用中反而應用更多。

j**a中最簡單的lru演算法實現,就是利用jdk的linkedhashmap,覆寫其中的removeeldestentry(map.entry)方法即可

如果你去看linkedhashmap的原始碼可知,lru演算法是通過雙向鍊錶來實現,當某個位置被命中,通過調整鍊錶的指向將該位置調整到頭位置,新加入的內容直接放在煉表頭,如此一來,最近被命中的內容就向煉表頭移動,需要替換時,鍊錶最後的位置就是最近最少使用的位置。

用於自己個人學習記錄,

參考**:

LruCache實現原理

lrucache 什麼是lrucache?lrucache實現原理是什麼?這兩個問題其實可以作為乙個問題來回答,知道了什麼是 lrucache,就只然而然的知道 lrucache 的實現原理 lru的全稱是least recently used 近期最少使用的!所以我們可以推斷出 lrucache ...

談談LruCache演算法的底層實現原理及其內部原始碼

我們在對資料進行操作的時候,為了避免流量或者效能的消耗,我們對於一些資料都會進行快取處理,而對資料的快取的要點不僅僅只有我們所熟悉的儲存快取和使用快取,還有刪除快取。對於新增和獲取快取很好理解,那麼為什麼還要對快取進行刪除吶?原因很簡單,因為我們的手機容量是有限的,如果我們拼命的寫入快取,那麼終有一...

談談LruCache演算法的底層實現原理及其內部原始碼

我們在對資料進行操作的時候,為了避免流量或者效能的消耗,我們對於一些資料都會進行快取處理,而對資料的快取的要點不僅僅只有我們所熟悉的儲存快取和使用快取,還有刪除快取。對於新增和獲取快取很好理解,那麼為什麼還要對快取進行刪除吶?原因很簡單,因為我們的手機容量是有限的,如果我們拼命的寫入快取,那麼終有一...