IOS缓存管理之YYCache使用
前言:
最近一直在致力于为公司app添加缓存功能,为了寻找一个最佳方案,这几天先做个技术预研,经过这两天的查找资料基本上确定了两个开源框架进行选择,这两个开源框架分别是:PINCache、YYCache,上篇已经简单介绍了PINCache使用,本篇主要来学习一下YYCache的使用方式,以及和PINCache性能的简单对比。
关于YYCache
1. 内存缓存(YYMemoryCache)
存储的单元是_YYLinkedMapNode,除了key和value外,还存储了它的前后Node的地址_prev,_next.整个实现基于_YYLinkedMap,它是一个双向链表,除了存储了字典_dic外,还存储了头结点和尾节点.它实现的功能很简单,就是:有新数据了插入链表头部,访问过的数据结点移到头部,内存紧张时把尾部的结点移除.就这样实现了淘汰算法.因为内存访问速度很快,锁占用的时间少,所以用的速度最快的OSSpinLockLock
2. 硬盘缓存(YYDiskCache)
采用的是文件和数据库相互配合的方式.有一个参数inlineThreshold,默认20KB,小于它存数据库,大于它存文件.能获得效率的提高.key:path,value:cache存储在NSMapTable里.根据path获得cache,进行一系列的set,get,remove操作更底层的是YYKVStorage,它能直接对sqlite和文件系统进行读写.每次内存超过限制时,select key, filename, size from manifest order by last_access_time desc limit ?1会根据时间排序来删除最近不常用的数据.硬盘访问的时间比较长,如果用OSSpinLockLock锁会造成CPU消耗过大,所以用的dispatch_semaphore_wait来做.
YYCache使用
1.同步方式
//模拟数据
NSString *value=@"I want to know who is lcj ?";
//模拟一个key
//同步方式
NSString *key=@"key";
YYCache *yyCache=[YYCache cacheWithName:@"LCJCache"];
//根据key写入缓存value
[yyCache setObject:value forKey:key];
//判断缓存是否存在
BOOL isContains=[yyCache containsObjectForKey:key];
NSLog(@"containsObject : %@", isContains?@"YES":@"NO");
//根据key读取数据
id vuale=[yyCache objectForKey:key];
NSLog(@"value : %@",vuale);
//根据key移除缓存
[yyCache removeObjectForKey:key];
//移除所有缓存
[yyCache removeAllObjects];
2.异步方式
//模拟数据
NSString *value=@"I want to know who is lcj ?";
//模拟一个key
//异步方式
NSString *key=@"key";
YYCache *yyCache=[YYCache cacheWithName:@"LCJCache"];
//根据key写入缓存value
[yyCache setObject:value forKey:key withBlock:^{
NSLog(@"setObject sucess");
}];
//判断缓存是否存在
[yyCache containsObjectForKey:key withBlock:^(NSString * _Nonnull key, BOOL contains) {
NSLog(@"containsObject : %@", contains?@"YES":@"NO");
}]; //根据key读取数据
[yyCache objectForKey:key withBlock:^(NSString * _Nonnull key, id<NSCoding> _Nonnull object) {
NSLog(@"objectForKey : %@",object);
}]; //根据key移除缓存
[yyCache removeObjectForKey:key withBlock:^(NSString * _Nonnull key) {
NSLog(@"removeObjectForKey %@",key);
}];
//移除所有缓存
[yyCache removeAllObjectsWithBlock:^{
NSLog(@"removeAllObjects sucess");
}]; //移除所有缓存带进度
[yyCache removeAllObjectsWithProgressBlock:^(int removedCount, int totalCount) {
NSLog(@"removeAllObjects removedCount :%d totalCount : %d",removedCount,totalCount);
} endBlock:^(BOOL error) {
if(!error){
NSLog(@"removeAllObjects sucess");
}else{
NSLog(@"removeAllObjects error");
}
}];
YYCache缓存LRU清理
LRU(Least Recently Used)算法大家都比较熟悉,翻译过来就是“最近最少使用”,LRU缓存就是使用这种原理实现,简单的说就是缓存一定量的数据,当超过设定的阈值时就把一些过期的数据删除掉,比如我们缓存10000条数据,当数据小于10000时可以随意添加,当超过10000时就需要把新的数据添加进来,同时要把过期数据删除,以确保我们最大缓存10000条,那怎么确定删除哪条过期数据呢,采用LRU算法实现的话就是将最老的数据删掉。接下来我们测试一下
YYCache *yyCache=[YYCache cacheWithName:@"LCJCache"];
[yyCache.memoryCache setCountLimit:];//内存最大缓存数据个数
[yyCache.memoryCache setCostLimit:*];//内存最大缓存开销 目前这个毫无用处
[yyCache.diskCache setCostLimit:*];//磁盘最大缓存开销
[yyCache.diskCache setCountLimit:];//磁盘最大缓存数据个数
[yyCache.diskCache setAutoTrimInterval:];//设置磁盘lru动态清理频率 默认 60秒
模拟一下清理
for(int i= ;i<;i++){
//模拟数据
NSString *value=@"I want to know who is lcj ?";
//模拟一个key
NSString *key=[NSString stringWithFormat:@"key%d",i];
[yyCache setObject:value forKey:key];
}
NSLog(@"yyCache.memoryCache.totalCost:%lu",(unsigned long)yyCache.memoryCache.totalCost);
NSLog(@"yyCache.memoryCache.costLimit:%lu",(unsigned long)yyCache.memoryCache.costLimit);
NSLog(@"yyCache.memoryCache.totalCount:%lu",(unsigned long)yyCache.memoryCache.totalCount);
NSLog(@"yyCache.memoryCache.countLimit:%lu",(unsigned long)yyCache.memoryCache.countLimit);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)( * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"yyCache.diskCache.totalCost:%lu",(unsigned long)yyCache.diskCache.totalCost);
NSLog(@"yyCache.diskCache.costLimit:%lu",(unsigned long)yyCache.diskCache.costLimit);
NSLog(@"yyCache.diskCache.totalCount:%lu",(unsigned long)yyCache.diskCache.totalCount);
NSLog(@"yyCache.diskCache.countLimit:%lu",(unsigned long)yyCache.diskCache.countLimit);
for(int i= ;i<;i++){
//模拟一个key
NSString *key=[NSString stringWithFormat:@"whoislcj%d",i];
id vuale=[yyCache objectForKey:key];
NSLog(@"key :%@ value : %@",key ,vuale);
}
});
YYCache和PINCache一样并没有实现基于最大内存开销进行LRU,不过YYCache实现了最大缓存数据个数进行LRU清理,这一点也是选择YYCache原因之一,对于YYCache磁盘LRU清理并不是及时清理,而是后台开启一个定时任务进行RLU清理操作,定时时间默认是60s。
YYCache与PINCache对比
对于我这里的使用场景大部分用于缓存json字符串,我这里就以存储字符串来对比一下写入与读取效率
1.写入性能对比
YYCache
//模拟数据
NSString *value=@"I want to know who is lcj ?";
//模拟一个key
NSString *key=@"key";
//YYCache
YYCache *yyCache=[YYCache cacheWithName:@"LCJCache"];
//写入数据
CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
[yyCache setObject:value forKey:key withBlock:^{
CFAbsoluteTime end = CFAbsoluteTimeGetCurrent(); NSLog(@" yyCache async setObject time cost: %0.5f", end - start);
}]; CFAbsoluteTime start1 = CFAbsoluteTimeGetCurrent();
[yyCache setObject:value forKey:key];
CFAbsoluteTime end1 = CFAbsoluteTimeGetCurrent();
NSLog(@" yyCache sync setObject time cost: %0.5f", end1 - start1);
运行结果

PINCache
//PINCache
//模拟数据
NSString *value=@"I want to know who is lcj ?";
//模拟一个key
NSString *key=@"key";
PINCache *pinCache=[PINCache sharedCache];
//写入数据
CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
[pinCache setObject:value forKey:key block:^(PINCache * _Nonnull cache, NSString * _Nonnull key, id _Nullable object) {
CFAbsoluteTime end = CFAbsoluteTimeGetCurrent(); NSLog(@" pincache async setObject time cost: %0.5f", end - start);
}]; CFAbsoluteTime start1 = CFAbsoluteTimeGetCurrent();
[pinCache setObject:value forKey:key];
CFAbsoluteTime end1 = CFAbsoluteTimeGetCurrent();
NSLog(@" pinCache sync setObject time cost: %0.5f", end1 - start1);
运行结果

通过上面的测试可以看出 同样大小的数据,无论同步方式还是异步方式,YYCache性能都要由于PINCache。
2.读取性能对比
YYCache
YYCache *yyCache=[YYCache cacheWithName:@"LCJCache"];
//模拟一个key
NSString *key=@"key";
CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
//读取数据
[yyCache objectForKey:key withBlock:^(NSString * _Nonnull key, id<NSCoding> _Nonnull object) {
CFAbsoluteTime end = CFAbsoluteTimeGetCurrent();
NSLog(@" yyCache async objectForKey time cost: %0.5f", end - start);
}]; CFAbsoluteTime start1 = CFAbsoluteTimeGetCurrent();
[yyCache objectForKey:key];
CFAbsoluteTime end1 = CFAbsoluteTimeGetCurrent();
NSLog(@" yyCache sync objectForKey time cost: %0.5f", end1 - start1);
运行结果:

PINCache
PINCache *pinCache=[PINCache sharedCache];
//模拟一个key
NSString *key=@"key";
CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
//读取数据
[pinCache objectForKey:key block:^(PINCache * _Nonnull cache, NSString * _Nonnull key, id _Nullable object) {
CFAbsoluteTime end = CFAbsoluteTimeGetCurrent();
NSLog(@" pincache async objectForKey time cost: %0.5f", end - start);
}] ; CFAbsoluteTime start1 = CFAbsoluteTimeGetCurrent();
[pinCache objectForKey:key];
CFAbsoluteTime end1 = CFAbsoluteTimeGetCurrent();
NSLog(@" pinCache objectForKey time cost: %0.5f", end1 - start1);
运行结果:

通过运行结果,在读取方面YYCache也是优于PINCache。
总结:
经过一番查阅资料和自己写例子测试,最终项目中决定使用YYCache进行缓存管理。
IOS缓存管理之YYCache使用的更多相关文章
- IOS缓存管理之PINCache使用
前言: 今年重点在于公司iOS架构的梳理工作,上周整理了http请求接口管理与解耦,接下来准备整理一下项目中的缓存处理,目前项目中使用的是PINCache,去年加入这个开源框架时并没有对这个框架进行了 ...
- iOS内存管理编程指南
iOS 内存管理 目录[-] 一:基本原则 二:成员变量的内存管理 三:容器对象与内存管理 四:稀缺资源的管理 五:AutoRelease 六:其他注意事项 iOS下内存管理的基本思想就是引用计数,通 ...
- HTML5 离线缓存管理库
一.HTML5离线缓存技术 支持离线缓存是HTML5中的一个重点,离线缓存就是让用户即使在断网的情况下依然可以正常的运行应用.传统的本地存储数据的方式有 localstorage,sessionsto ...
- Spring自定义缓存管理及配置Ehcache缓存
spring自带缓存.自建缓存管理器等都可解决项目部分性能问题.结合Ehcache后性能更优,使用也比较简单. 在进行Ehcache学习之前,最好对Spring自带的缓存管理有一个总体的认识. 这篇文 ...
- iOS内存管理
iOS内存管理的方式是引用计数机制.分为MRC(人式引用计数)和ARC(自动引用计数). 为什么要学习内存管理? 内存管理方式是引用计数机制,通过控制对象的引用计数来实现操作对象的功能.一个对象的生命 ...
- 【Bugly干货分享】iOS内存管理:从MRC到ARC实践
Bugly 技术干货系列内容主要涉及移动开发方向,是由Bugly邀请腾讯内部各位技术大咖,通过日常工作经验的总结以及感悟撰写而成,内容均属原创,转载请标明出处. 对于iOS程序员来说,内存管理是入门的 ...
- 基于吉日嘎拉的通用权限管理WebForm版扩展:字典选项管理和缓存管理
关于字典管理,其实就是2个表,一个表记录字典和对应表,另一个表记录字典内容.我这里改名为字典选项,其实是一个意思.直接上图: 这里的字典选项是分子系统的,每个子系统可以有自己的单独字典,方便管理.但是 ...
- [js开源组件开发]localStorage-cache本地存储的缓存管理
localStorage-cache本地存储的缓存管理 距离上次的组件开发有近三个月的时间了,最近一直在做一些杂事,无法静下心来写写代码,也是在学习emberjs,在emberjs中有一个很重要的东西 ...
- iOS内存管理个人总结
一.变量,本质代表一段可以操作的内存,她使用方式无非就是内存符号化+数据类型 1.保存变量有三个区域: 1>静态存储区 2>stack 3>heap 2.变量又根据声明的位置有两种称 ...
随机推荐
- Python3基础 用 函数递归求解 一个数字的阶乘
镇场诗: 诚听如来语,顿舍世间名与利.愿做地藏徒,广演是经阎浮提. 愿尽吾所学,成就一良心博客.愿诸后来人,重现智慧清净体.-------------------------------------- ...
- jq动态添加的元素触发绑定事件无效
<div class='a'> <div class='b'> </div> 其中$('.a')是html页面的元素,$('.b')是jq动态添加的元素.$(&qu ...
- phpcms v9文章页调用点击量方法
1.在页面加载" 2.调用统计点击的标签:: 3.最后,在写上这一句:" phpcms v9增加文章随机点击数的方法 找到文件count.php(网站根目录/api) 查找第50行 ...
- js模块化开发——模块的写法
随着网站逐渐变成"互联网应用程序",嵌入网页的Javascript代码越来越庞大,越来越复杂. 网页越来越像桌面程序,需要一个团队分工协作.进度管理.单元测试等等......开发者 ...
- animate的{queue:false,duration:400}意思
示例:$(document).ready(function(){ $('.tmplS').hover(function(){ $(".cover", this).stop().an ...
- easyui datagrid分页参数获取
$("#btnDataExport").click(function () { $.messager.show({ title: '导出提示', msg: '每次导出一页商户数据, ...
- LINQ to Sql系列二 简单查询和联接查询
这一篇文章主要总结LINQ to sql的简单查询(单表查询)和联接查询(多表查询) 单表查询 需求是我们要输出TClass表中的结果.使用了from-in-select语句,代码如下: public ...
- 不常见但很有用的chrome调试工具使用方法
前面的话 对于chrome调试工具,常用的是elements标签.console标签.sources标签和network标签.但实际上,还有一些不太常见但相当实用的方法可以提高网页调试效率.本文将 ...
- RxJava2出现:Unable to create call adapter for io.reactivex.Flowable
前面一直使用的是Rxjava 1.x 版本,最近 Rxjava 2.x 版本发布了,并且支持了背压,便换成了 Rxjava 2.x 版本.更换之后出现了下面的错误. Caused by: java.l ...
- TCP&UDP
TCP(传输控制协议) 建立连接,形成传输数据的通道 在连接中进行大数据传输(数据大小不受限制) 通过三次握手完成连接,是可靠协议,安全送达(三次握手向服务器发送请求,响应请求回复,发送数据) 必须建 ...