前言:

最近一直在致力于为公司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使用的更多相关文章

  1. IOS缓存管理之PINCache使用

    前言: 今年重点在于公司iOS架构的梳理工作,上周整理了http请求接口管理与解耦,接下来准备整理一下项目中的缓存处理,目前项目中使用的是PINCache,去年加入这个开源框架时并没有对这个框架进行了 ...

  2. iOS内存管理编程指南

    iOS 内存管理 目录[-] 一:基本原则 二:成员变量的内存管理 三:容器对象与内存管理 四:稀缺资源的管理 五:AutoRelease 六:其他注意事项 iOS下内存管理的基本思想就是引用计数,通 ...

  3. HTML5 离线缓存管理库

    一.HTML5离线缓存技术 支持离线缓存是HTML5中的一个重点,离线缓存就是让用户即使在断网的情况下依然可以正常的运行应用.传统的本地存储数据的方式有 localstorage,sessionsto ...

  4. Spring自定义缓存管理及配置Ehcache缓存

    spring自带缓存.自建缓存管理器等都可解决项目部分性能问题.结合Ehcache后性能更优,使用也比较简单. 在进行Ehcache学习之前,最好对Spring自带的缓存管理有一个总体的认识. 这篇文 ...

  5. iOS内存管理

    iOS内存管理的方式是引用计数机制.分为MRC(人式引用计数)和ARC(自动引用计数). 为什么要学习内存管理? 内存管理方式是引用计数机制,通过控制对象的引用计数来实现操作对象的功能.一个对象的生命 ...

  6. 【Bugly干货分享】iOS内存管理:从MRC到ARC实践

    Bugly 技术干货系列内容主要涉及移动开发方向,是由Bugly邀请腾讯内部各位技术大咖,通过日常工作经验的总结以及感悟撰写而成,内容均属原创,转载请标明出处. 对于iOS程序员来说,内存管理是入门的 ...

  7. 基于吉日嘎拉的通用权限管理WebForm版扩展:字典选项管理和缓存管理

    关于字典管理,其实就是2个表,一个表记录字典和对应表,另一个表记录字典内容.我这里改名为字典选项,其实是一个意思.直接上图: 这里的字典选项是分子系统的,每个子系统可以有自己的单独字典,方便管理.但是 ...

  8. [js开源组件开发]localStorage-cache本地存储的缓存管理

    localStorage-cache本地存储的缓存管理 距离上次的组件开发有近三个月的时间了,最近一直在做一些杂事,无法静下心来写写代码,也是在学习emberjs,在emberjs中有一个很重要的东西 ...

  9. iOS内存管理个人总结

    一.变量,本质代表一段可以操作的内存,她使用方式无非就是内存符号化+数据类型 1.保存变量有三个区域: 1>静态存储区 2>stack 3>heap 2.变量又根据声明的位置有两种称 ...

随机推荐

  1. ndk-stack 调试 android c++ 代码崩溃位置

    在android下面使用jni来调用c++,在开发游戏是非常正常的.但是要调试c++部分却是非常麻烦的问题.如果快速定位崩溃位置呢.NDK提供了一个小工具ndk-stack. 首先,我们先配置环境,把 ...

  2. mongodb学习(五) 查询

    1. 按条件查询: db.users.find({"name":"MM1"}) 2.find的第二个参数可以指定要返回的字段:这里1 表示要显示的字段,0 表示 ...

  3. javascript中的__proto__和prototype

    一.2个参考网址: http://icekiller110.iteye.com/blog/1566768 http://www.cnblogs.com/snandy/archive/2012/09/0 ...

  4. zip-auto.sh

    #!/bin/sh #auto zip package #Define Path #####test######### mkdir -p /root/shell/test1 /root/shell/t ...

  5. 大数据全栈式开发语言 – Python

    前段时间,ThoughtWorks在深圳举办一次社区活动上,有一个演讲主题叫做“Fullstack JavaScript”,是关于用JavaScript进行前端.服务器端,甚至数据库(MongoDB) ...

  6. codeforces 755D. PolandBall and Polygon

    D. PolandBall and Polygon time limit per test 4 seconds memory limit per test 256 megabytes input st ...

  7. curl远程传输工具

    /** * curl远程传输工具 */ public function post_curl($url,$body,$header,$type='POST'){ $ch = curl_init(); c ...

  8. 详解JavaScript中的事件处理

    在漫长的演变史,我们已经告别了内嵌式的事件处理方式(直接将事件处理器放在HTML元素之内来使用),今天的事件,它已是DOM的重要组成部分,遗憾的是,IE继续保留它最早在IE4.0中实现的事件模型,以后 ...

  9. shell读取文件的每一行

    写法一: ---------------------------------------------------------------------------- #!/bin/bash while ...

  10. 使用IDA静态分析解密《舰娘Collection》的lua脚本

    好久没写东西了,换工作之后忙得一比.你说创业?风太大没听清啊看了看以前写的东西,觉得以前写得太严肃了,从现在开始要轻松一点,要做一名逗逼码农. 本文不会介绍破解的细节,最终完成破解所编写的代码也不会公 ...