爲了設計一個比較好的磁盤緩存,我調查了大量的開源庫,包括 TMDiskCache、PINDiskCache、SDWebImage、FastImageCache 等,也調查了一些閉源的實現,包括 NSURLCache、Facebook 的 FBDiskCache 等。他們的實現技術大體分爲三類:基於文件讀寫、基於 mmap 文件內存映射、基於數據庫。html
TMDiskCache, PINDiskCache, SDWebImage 等緩存,都是基於文件系統的,即一個 Value 對應一個文件,經過文件讀寫來緩存數據。他們的實現都比較簡單,性能也都相近,缺點也是一樣的:不方便擴展、沒有元數據、難以實現較好的淘汰算法、數據統計緩慢。算法
FastImageCache 採用的是 mmap 將文件映射到內存。用過 MongoDB 的人應該很熟悉 mmap 的缺陷:熱數據的文件不要超過物理內存大小,否則 mmap 會致使內存交換嚴重下降性能;另外內存中的數據是定時 flush 到文件的,若是數據還未同步時程序掛掉,就會致使數據錯誤。拋開這些缺陷來講,mmap 性能很是高。sql
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 或其餘淘汰算法
缺點:單條數據較大的時候讀寫性能較差。spa