为了设计一个比较好的磁盘缓存,我调查了大量的开源库,包括 TMDiskCache、PINDiskCache、SDWebImage、FastImageCache 等,也调查了一些闭源的实现,包括 NSURLCache、Facebook 的 FBDiskCache 等。他们的实现技术大致分为三类:基于文件读写、基于 mmap 文件内存映射、基于数据库。
TMDiskCache, PINDiskCache, SDWebImage 等缓存,都是基于文件系统的,即一个 Value 对应一个文件,通过文件读写来缓存数据。他们的实现都比较简单,性能也都相近,缺点也是同样的:不方便扩展、没有元数据、难以实现较好的淘汰算法、数据统计缓慢。
FastImageCache 采用的是 mmap 将文件映射到内存。用过 MongoDB 的人应该很熟悉 mmap 的缺陷:热数据的文件不要超过物理内存大小,不然 mmap 会导致内存交换严重降低性能;另外内存中的数据是定时 flush 到文件的,如果数据还未同步时程序挂掉,就会导致数据错误。抛开这些缺陷来说,mmap 性能非常高。
NSURLCache、FBDiskCache 都是基于 SQLite 数据库的。基于数据库的缓存可以很好的支持元数据、扩展方便、数据统计速度快,也很容易实现 LRU 或其他淘汰算法,唯一不确定的就是数据库读写的性能,为此我评测了一下 SQLite 在真机上的表现。iPhone 6 64G 下,SQLite 写入性能比直接写文件要高,但读取性能取决于数据大小:当单条数据小于 20K 时,数据越小 SQLite 读取性能越高;单条数据大于 20K 时,直接写为文件速度会更快一些。这和 SQLite 官网的描述基本一致。另外,直接从官网下载最新的 SQLite 源码编译,会比 iOS 系统自带的 sqlite3.dylib 性能要高很多。基于 SQLite 的这种表现,磁盘缓存最好是把 SQLite 和文件存储结合起来:key-value 元数据保存在 SQLite 中,而 value 数据则根据大小不同选择 SQLite 或文件存储。NSURLCache 选定的数据大小的阈值是 16K;FBDiskCache 则把所有 value 数据都保存成了文件。
我的 YYDiskCache 也是采用的 SQLite 配合文件的存储方式,在 iPhone 6 64G 上的性能基准测试结果见下图。在存取小数据 (NSNumber) 时,YYDiskCache 的性能远远高出基于文件存储的库;而较大数据的存取性能则比较接近了。但得益于 SQLite 存储的元数据,YYDiskCache 实现了 LRU 淘汰算法、更快的数据统计,更多的容量控制选项。
https://blog.ibireme.com/2015/10/26/yycache/
iOS缓存设计(阅读笔记)
市面上常见的缓存库分类
基于文件系统 :TMDiskCache, PINDiskCache, SDWebImage
优点:实现都比较简单
缺点:不方便扩展、没有元数据、难以实现较好的淘汰算法、数据统计缓慢。
基于mmap :MMKV, FastImageCache,
优点:直接在内存中操作文件,对比文件 I/O 更快
缺点:热数据的文件不要超过物理内存大小,不然 mmap 会导致内存交换严重降低性能,如果数据还未同步时程序挂掉,就会导致数据错误
(关于mmap详解)
基于 SQLite : YapDataBase, FMDB,NSURLCache、FBDiskCache
优点: 支持元数据、扩展方便、数据统计速度快,也很容易实现 LRU 或其他淘汰算法
缺点:单条数据较大的时候读写性能较差。
作者:10m每秒滑行
链接:https://www.jianshu.com/p/10331a0941c4
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。