LRU缓存淘汰算法

来源:互联网 发布:百川江湖淘宝 编辑:程序博客网 时间:2024/06/02 13:16

原理:

LRU(最近最少使用)算法根据数据的访问频率,将最近访问的放在队头,将最少访问的放在队尾,当缓存在一定范围内时,就将最少访问的数据删除,对于经常访问的数据就留在内存中,提高系统性能,正常是用在操作系统的cache命中中使用。

实现:

在Android的HWUI中,通过使用LruCaches来保存使用的资源,从而提高HWUI的渲染性能,又不至于浪费太多的内存。


如图所示,用一个双向链表用于保存当前的Caches节点,队头的为最年轻的节点,队尾的为最老的节点,同时用一个map来保存当前的节点信息,便于提高查找的性能。
1. 当取得一个节点时(get),如果该节点在map中,则将取得当前节点在链表中的位置,将当前节点从链表中移除,同时将该节点插入到链表头的位置,即作为最年轻的节点。
2. 当需要插入一个节点时,直接将该节点插入到链表表头的位置。(Youngest)
3. 当需要删除最尾部的节点时,直接将当前的Oldest删除,将Oldest的父亲作为最老的节点。


如下代码所示,通过使用模板类实现LruCache算法,便于以后的使用:

#pragma once#include <map>using std::map;template<class TKey, class TValue>class OnEntryCallBack{public:virtual ~OnEntryCallBack(){}virtual void deleteOp(TKey& key, TValue& value) {};virtual void dump(const TKey& key, const TValue& value){}};template<class TKey, class TValue>class LruCaches{struct Entry;public:LruCaches();~LruCaches();void setEntryCallBackListen(OnEntryCallBack<TKey, TValue>* listen){mListen = listen;}int size(){return mTable.size();}bool put(const TKey& key, const TValue& value);const TValue& get(const TKey& key);bool remove(const TKey& key);bool removeOldest();void clear();void dump();private:void attachToCache(Entry* entry);void detachFromCache(Entry* entry);bool removeEntrye(Entry* entry);private:struct Entry{TKey mKey;TValue mValue;Entry* mParent;Entry* mChild;Entry(const TKey& key, const TValue& value){mKey = key;mValue = value;mParent = mChild = NULL;}};private:map<TKey, Entry*> mTable;Entry* mYoungest;Entry* mOldest;OnEntryCallBack<TKey, TValue>* mListen;};template<class TKey, class TValue>LruCaches<TKey, TValue>::LruCaches(){mListen = NULL;mYoungest = mOldest = NULL;}template<class TKey, class TValue>LruCaches<TKey, TValue>::~LruCaches(){clear();}template<class TKey, class TValue>bool LruCaches<TKey, TValue>::put(const TKey& key, const TValue& value){Entry* entry = NULL;map<TKey, Entry*>::iterator iter = mTable.find(key);if (iter == mTable.end()){entry = new Entry(key, value);mTable[key] = entry;attachToCache(entry);}else{return false;}return true;}template<class TKey, class TValue>void LruCaches<TKey, TValue>::attachToCache(Entry* entry){if (NULL == mYoungest && NULL == mOldest){mYoungest = mOldest = entry;}else{mYoungest->mParent = entry;entry->mChild = mYoungest;mYoungest = entry;}}template<class TKey, class TValue>void LruCaches<TKey, TValue>::detachFromCache(Entry* entry){if (NULL != entry->mParent){entry->mParent->mChild = entry->mChild;}else{mYoungest = entry->mChild;}if (NULL != entry->mChild){entry->mChild->mParent = entry->mParent;}else{mOldest = entry->mParent;}entry->mParent = entry->mChild = NULL;}template<class TKey, class TValue>const TValue& LruCaches<TKey, TValue>::get(const TKey& key){Entry* entry = NULL;map<TKey, Entry*>::iterator iter = mTable.find(key);if (iter == mTable.end()){return NULL;}else{entry = iter->second;detachFromCache(entry);}attachToCache(entry);return entry->mValue;}template<class TKey, class TValue>bool LruCaches<TKey, TValue>::remove(const TKey& key){map<TKey, Entry*>::iterator iter = mTable.find(key);if (iter == mTable.end()){return false;}return removeEntrye(iter->second);}template<class TKey, class TValue>bool LruCaches<TKey, TValue>::removeOldest(){if (NULL == mOldest){return false;}return removeEntrye(mOldest);}template<class TKey, class TValue>bool LruCaches<TKey, TValue>::removeEntrye(Entry* entry){detachFromCache(entry);map<TKey, Entry*>::iterator iter = mTable.find(entry->mKey);if (iter == mTable.end()){return false;}mTable.erase(iter);mListen->deleteOp(entry->mKey, entry->mValue);delete entry;entry = NULL;return true;}template<class TKey, class TValue>void LruCaches<TKey, TValue>::clear(){map<TKey, Entry*>::iterator iter = mTable.begin();for (iter; iter != mTable.end(); iter++){mListen->deleteOp(iter->second->mKey, iter->second->mValue);delete iter->second;}mTable.clear();}template<class TKey, class TValue>void LruCaches<TKey, TValue>::dump(){Entry* tmp = mYoungest;for (tmp; tmp != NULL; tmp = tmp->mChild){mListen->dump(tmp->mKey, tmp->mValue);}}

使用方式:

class LruTest : public OnEntryCallBack<int, int>{public:LruTest(){Caches.setEntryCallBackListen(this);}~LruTest(){}void init(){Caches.put(1, 10);Caches.put(2, 20);Caches.put(3, 30);Caches.put(4, 40);Caches.get(2);cout<<endl;Caches.get(1);cout<<endl;Caches.get(3);cout<<endl;Caches.get(2);cout<<endl;Caches.removeOldest();Caches.dump();cout<<endl;Caches.removeOldest();Caches.dump();cout<<endl;Caches.removeOldest();Caches.dump();cout<<endl;Caches.removeOldest();Caches.dump();Caches.size();Caches.clear();Caches.dump();}virtual void dump(const int & key, const int & value){cout<<"key="<<key <<"   value="<<value<<endl;}private:LruCaches<int, int> Caches;};

具体也可以参看Android源码:

system/core/include/utils/LruCache.h

0 0
原创粉丝点击