緩存算法 前端
沒有人能說清哪一種緩存算法優於其餘的緩存算法 算法
Least Frequently Used(LFU): 數據庫
你們好,我是 LFU,我會計算爲每一個緩存對象計算他們被使用的頻率。我會把最不經常使用的緩存對象踢走。 瀏覽器
Least Recently User(LRU): 緩存
我是 LRU 緩存算法,我把最近最少使用的緩存對象給踢走。 性能
我老是須要去了解在何時,用了哪一個緩存對象。若是有人想要了解我爲何總能把最近最少使用的對象踢掉,是很是困難的。 指針
瀏覽器就是使用了我(LRU)做爲緩存算法。新的對象會被放在緩存的頂部,當緩存達到了容量極限,我會把底部的對象踢走,而技巧就是:我會把最新被訪問的緩存對象,放到緩存池的頂部。 對象
因此,常常被讀取的緩存對象就會一直呆在緩存池中。有兩種方法能夠實現我,array 或者是 linked list。 隊列
個人速度很快,我也能夠被數據訪問模式適配。我有一個你們庭,他們均可以完善我,甚至作的比我更好(我確實有時會嫉妒,可是不要緊)。我家庭的一些成員包括 LRU2 和 2Q,他們就是爲了完善 LRU 而存在的。 內存
Least Recently Used 2(LRU2):
我是 Least Recently Used 2,有人叫我最近最少使用 twice,我更喜歡這個叫法。我會把被兩次訪問過的對象放入緩存池,當緩存池滿了以後,我會把有兩次最少使用的緩存對象踢走。由於須要跟蹤對象2次,訪問負載就會隨着緩存池的增長而增長。若是把我用在大容量的緩存池中,就會有問題。另外,我還須要跟蹤那麼不在緩存的對象,由於他們尚未被第二次讀取。我比LRU好,並且是 adoptive to access 模式 。
Two Queues(2Q):
我是 Two Queues;我把被訪問的數據放到 LRU 的緩存中,若是這個對象再一次被訪問,我就把他轉移到第二個、更大的 LRU 緩存。
我踢走緩存對象是爲了保持第一個緩存池是第二個緩存池的1/3。當緩存的訪問負載是固定的時候,把 LRU 換成 LRU2,就比增長緩存的容量更好。這種機制使得我比 LRU2 更好,我也是 LRU 家族中的一員,並且是 adoptive to access 模式 。
Adaptive Replacement Cache(ARC):
我是 ARC,有人說我是介於 LRU 和 LFU 之間,爲了提升效果,我是由2個 LRU 組成,第一個,也就是 L1,包含的條目是最近只被使用過一次的,而第二個 LRU,也就是 L2,包含的是最近被使用過兩次的條目。所以, L1 放的是新的對象,而 L2 放的是經常使用的對象。因此,別人纔會認爲我是介於 LRU 和 LFU 之間的,不過不要緊,我不介意。
我被認爲是性能最好的緩存算法之一,可以自調,而且是低負載的。我也保存着歷史對象,這樣,我就能夠記住那些被移除的對象,同時,也讓我能夠看到被移除的對象是否能夠留下,取而代之的是踢走別的對象。個人記憶力不好,可是我很快,適用性也強。
Most Recently Used(MRU):
我是 MRU,和 LRU 是對應的。我會移除最近最多被使用的對象,你必定會問我爲何。好吧,讓我告訴你,當一次訪問過來的時候,有些事情是沒法預測的,而且在緩存系統中找出最少最近使用的對象是一項時間複雜度很是高的運算,這就是爲何我是最好的選擇。
我是數據庫內存緩存中是多麼的常見!每當一次緩存記錄的使用,我會把它放到棧的頂端。當棧滿了的時候,你猜怎麼着?我會把棧頂的對象給換成新進來的對象!
First in First out(FIFO):
我是先進先出,我是一個低負載的算法,而且對緩存對象的管理要求不高。我經過一個隊列去跟蹤全部的緩存對象,最近最經常使用的緩存對象放在後面,而更早的緩存對象放在前面,當緩存容量滿時,排在前面的緩存對象會被踢走,而後把新的緩存對象加進去。我很快,可是我並不適用。
Second Chance:
你們好,我是 second chance,我是經過 FIFO 修改而來的,被你們叫作 second chance 緩存算法,我比 FIFO 好的地方是我改善了 FIFO 的成本。我是 FIFO 同樣也是在觀察隊列的前端,可是很FIFO的馬上踢出不一樣,我會檢查即將要被踢出的對象有沒有以前被使用過的標誌(1一個 bit 表示),沒有沒有被使用過,我就把他踢出;不然,我會把這個標誌位清除,而後把這個緩存對象當作新增緩存對象加入隊列。你能夠想象就這就像一個環隊列。當我再一次在隊頭碰到這個對象時,因爲他已經沒有這個標誌位了,因此我馬上就把他踢開了。我在速度上比 FIFO 快。
CLock:
我是 Clock,一個更好的 FIFO,也比 second chance 更好。由於我不會像 second chance 那樣把有標誌的緩存對象放到隊列的尾部,可是也能夠達到 second chance 的效果。
我持有一個裝有緩存對象的環形列表,頭指針指向列表中最老的緩存對象。當緩存 miss 發生而且沒有新的緩存空間時,我會問問指針指向的緩存對象的標誌位去決定我應該怎麼作。若是標誌是0,我會直接用新的緩存對象替代這個緩存對象;若是標誌位是1,我會把頭指針遞增,而後重複這個過程,知道新的緩存對象可以被放入。我比 second chance 更快。
Simple time-based:
我是 simple time-based 緩存算法,我經過絕對的時間週期去失效那些緩存對象。對於新增的對象,我會保存特定的時間。我很快,可是我並不適用。
Extended time-based expiration:
我是 extended time-based expiration 緩存算法,我是經過相對時間去失效緩存對象的;對於新增的緩存對象,我會保存特定的時間,好比是每5分鐘,天天的12點。
Sliding time-based expiration:
我是 sliding time-based expiration,與前面不一樣的是,被我管理的緩存對象的生命起點是在這個緩存的最後被訪問時間算起的。我很快,可是我也不太適用。
其餘的緩存算法還考慮到了下面幾點:
成本:若是緩存對象有不一樣的成本,應該把那些難以得到的對象保存下來。
容量:若是緩存對象有不一樣的大小,應該把那些大的緩存對象清除,這樣就可讓更多的小緩存對象進來了。
時間:一些緩存還保存着緩存的過時時間。電腦會失效他們,由於他們已通過期了。
根據緩存對象的大小而無論其餘的緩存算法多是有必要的。