内存缓存那些事

内存缓存

缓存分为2类,内存缓存和磁盘缓存,今天说的是内存缓存。

内存缓存实现很多种方式,最简单的是就是用NSMutableDictionary来实现,性能也是最好的,但是它不是线程安全的,而且也没有存到一定程度删除的机制。

内存缓存实现的比较好的有苹果官方的NSCache,ibireme的YYMemoryCache,Pinterest的PINMemoryCache。他们都是线程安全的,也都提供了数量限制、总容量限制、内存警告清空缓存等功能。

这是ibireme提供的他们性能对比图

image

NSCache

NSCache 是苹果提供的一个简单的内存缓存,它有着和NSDictionary 类似的 API,不同点是它是线程安全的,并且不会 retain key。NSCache 底层并没有用 NSDictionary 等已有的类,而是直接调用了 libcache.dylib,其中线程安全是由 pthread_mutex 完成的。还有一点就是它的读取性能要比存取性能要好。

NSCache 有好多知名的三方库在用,比如SDWebImageAFNetworking等。网上有很多关于NSCache的用法教程,这里就不多介绍。

推荐一篇关于它用法的博客

http://www.wenghengcong.com/2016/03/iOS系统中缓存的使用/

YYMemoryCache

YYMemoryCacheibireme开源的内存缓存库,它的性能是比较好的,今天主要讲一下它的实现。

特征

  • LRU淘汰算法
  • 收到内存警告时可精准控制行为
  • 对象数量限制, 总容量限制, 存活时间限制
  • 查询和插入时, 并不是通过遍历双向链表, 而是使用字典hash表快速查找到指定结点, 保证效率

主要手段

  • CFMutableDictionaryRef来实现数据的实际存储;
  • 使用OSSpinLockLock来保证线程的安全 (之后改为pthread_mutex_lock)
  • 使用_YYLinkedMapNode_YYLinkedMap来组织数据的存储结构
  • 使用YYMemoryCache来组织对数据的各种操作

不再安全的 OSSpinLock

LRU淘汰算法也可以叫做最近最少使用,看下面这张图比较容易理解。


image
它的实现主要有3步:
1、新数据插入到链表头部;
2、每当缓存命中(即缓存数据被访问),则将数据移到链表头部;
3、当链表满的时候,将链表尾部的数据丢弃。

YYMemoryCache里面用双向链表NSMutableDictionry的方式来实现LRU淘汰算法。

关于双向链表可以看下面这个博客
http://blog.csdn.net/wangzhen209/article/details/8180462