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.变量又根据声明的位置有两种称 ...
随机推荐
- ndk-stack 调试 android c++ 代码崩溃位置
在android下面使用jni来调用c++,在开发游戏是非常正常的.但是要调试c++部分却是非常麻烦的问题.如果快速定位崩溃位置呢.NDK提供了一个小工具ndk-stack. 首先,我们先配置环境,把 ...
- mongodb学习(五) 查询
1. 按条件查询: db.users.find({"name":"MM1"}) 2.find的第二个参数可以指定要返回的字段:这里1 表示要显示的字段,0 表示 ...
- javascript中的__proto__和prototype
一.2个参考网址: http://icekiller110.iteye.com/blog/1566768 http://www.cnblogs.com/snandy/archive/2012/09/0 ...
- zip-auto.sh
#!/bin/sh #auto zip package #Define Path #####test######### mkdir -p /root/shell/test1 /root/shell/t ...
- 大数据全栈式开发语言 – Python
前段时间,ThoughtWorks在深圳举办一次社区活动上,有一个演讲主题叫做“Fullstack JavaScript”,是关于用JavaScript进行前端.服务器端,甚至数据库(MongoDB) ...
- codeforces 755D. PolandBall and Polygon
D. PolandBall and Polygon time limit per test 4 seconds memory limit per test 256 megabytes input st ...
- curl远程传输工具
/** * curl远程传输工具 */ public function post_curl($url,$body,$header,$type='POST'){ $ch = curl_init(); c ...
- 详解JavaScript中的事件处理
在漫长的演变史,我们已经告别了内嵌式的事件处理方式(直接将事件处理器放在HTML元素之内来使用),今天的事件,它已是DOM的重要组成部分,遗憾的是,IE继续保留它最早在IE4.0中实现的事件模型,以后 ...
- shell读取文件的每一行
写法一: ---------------------------------------------------------------------------- #!/bin/bash while ...
- 使用IDA静态分析解密《舰娘Collection》的lua脚本
好久没写东西了,换工作之后忙得一比.你说创业?风太大没听清啊看了看以前写的东西,觉得以前写得太严肃了,从现在开始要轻松一点,要做一名逗逼码农. 本文不会介绍破解的细节,最终完成破解所编写的代码也不会公 ...