LRU缓存淘汰算法

原理:

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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值