今天网上学习了下LFU、LRU这两种缓存淘汰机制,觉得很有意思,有些东西理解的 不是太到位,暂时记录下来。
LFU:
根据数据被访问的频率进行淘汰,现在你使用频率越高,将来使用到的频率也会高
1:新数据进入队列 (新数据块的引用计数为1),每次加入新数据时,整个队列就会重新排列;
2:不需要的数据淘汰;
3:引用计数如果相同时,根据时间先后顺序进行排列;
4:整体是根据引用计数进行排列,引用计数越大越在上面,引用1次,引用计数加1;
这种方式:需要维护队列中所有数据的访问记录,每个数据块都要维护对应的引用计数。由此联想,所有数据块的访问记录都需要维护,用引用计数去进行队列元素排序,内存消耗很高。
LRU:
- normal:
数据近期被使用过,将来被使用到的几率很高
1:加入新的数据
2:队列空间满了的时候,尾部的数据会被淘汰掉
3:如果要访问队列中的数据,该数据会被移动到队列的头部
频繁地访问,会造成数据被访问到的几率会下降,此外,这种normal模式也叫做LRU-1,即最近使用过1次。
- special:
LRU-K:
(k:最近使用的次数,当访问某个数据块达到k次,该数据块会被移动到缓存队列中)
1:新数据加入
2:淘汰数据(这个地方和LRU尾部淘汰是一个道理)
3:某个数据块被访问次数达到k次,每次都会重新排列缓存队列
4:根据时间进行排列
5:插入第k访问时,淘汰距离这次插入时间最久的数据,即淘汰缓存队列中时间最久的数据块
LRU-K:记录被访问过的数据,记录他们的访问次数,缓存列表基于时间排列,基于时间淘汰数据块;内存消耗会比LRU-1更大
例子分析:
YYCache:(引用PPNetWorking这个工具中缓存的几段代码)
写入:
+ (void)setHttpCache:(id)httpData URL:(NSString *)URL parameters:(NSDictionary *)parameters
{
NSString *cacheKey = [self cacheKeyWithURL:URL parameters:parameters];
//异步缓存,不会阻塞主线程
[[YYCache cacheWithName:NetworkResponseCache] setObject:httpData forKey:cacheKey withBlock:nil];
}
读取:
+ (id)httpCacheForURL:(NSString *)URL parameters:(NSDictionary *)parameters
{
NSString *cacheKey = [self cacheKeyWithURL:URL parameters:parameters];
return [[YYCache cacheWithName:NetworkResponseCache] objectForKey:cacheKey];
}
唯一键:
+ (NSString *)cacheKeyWithURL:(NSString *)URL parameters:(NSDictionary *)parameters
{
if(!parameters){return URL;};
// 将参数字典转换成字符串
NSData *stringData = [NSJSONSerialization dataWithJSONObject:parameters options:0 error:nil];
NSString *paraString = [[NSString alloc] initWithData:stringData encoding:NSUTF8StringEncoding];
// 将URL与转换好的参数字符串拼接在一起,成为最终存储的KEY值
NSString *cacheKey = [NSString stringWithFormat:@"%@%@",URL,paraString];
return cacheKey;
}