存儲技術
- 基于文件讀寫
- 基于 mmap 文件內存映射
- 基于數(shù)據(jù)庫
基于文件系統(tǒng)
SDWebImage 等緩存:一個 Value 對應一個文件贮缕。
不方便擴展久妆、沒有元數(shù)據(jù)、難以實現(xiàn)較好的淘汰算法跷睦、數(shù)據(jù)統(tǒng)計緩慢。
Memory Map-mmap
缺點:
熱數(shù)據(jù)的文件不要超過物理內存大小肋演,不然 mmap 會導致內存交換嚴重降低性能抑诸。
內存中的數(shù)據(jù)是定時 flush 到文件的烂琴,如果數(shù)據(jù)還未同步時程序掛掉,就會導致數(shù)據(jù)錯誤蜕乡。
優(yōu)點:
普通讀取文件奸绷。
disk -> 緩存 -> 內存中
普通寫文件
內存操作 -> 緩存 ->disk
mmap 內存操作 -> disk
mmap
比如文件大小為50k。會在內存中申請>50 具體是4k的整數(shù)倍层玲。所以此處可以是52k的內存号醉。
然后你就在0-50k的區(qū)域內進行讀寫,過一段時間辛块,會把內存中的數(shù)據(jù)同步到disk中畔派。
因為是相當于對內存的讀寫,所以讀寫速度很快润绵。
Link
數(shù)據(jù)庫
SQLite
- 寫入:數(shù)據(jù)庫大于直接寫入文件线椰。
- 讀取:
- 大于20k尘盼,文件讀取更快憨愉。
- 小于20k,數(shù)據(jù)庫的讀取快
鎖的使用
OSSpinLock卿捎,自旋鎖配紫,適合內存緩存的存取。
dispatch_semaphore午阵,等待時不會消耗 CPU 資源躺孝,適合磁盤緩存。
源碼分析
YYMemoryCache
_YYLinkedMapNode
_YYLinkedMapNode *_prev;
_YYLinkedMapNode *_next;
id _key;
id _value;
NSUInteger _cost; // The cost with which to associate the key-value pair.
NSTimeInterval _time; // 插入的時間,到時候可以依據(jù)這個清除超時對象
雙向鏈表中的一個節(jié)點趟庄。
_YYLinkedMap
CFMutableDictionaryRef _dic; // do not set object directly
NSUInteger _totalCost;
NSUInteger _totalCount;
_YYLinkedMapNode *_head; // MRU, do not change it directly
_YYLinkedMapNode *_tail; // LRU, do not change it directly
手動維持一個支持LRU (least-recently-used)的哈希表括细。
YYMemoryCache
pthread_mutex_t _lock;
_YYLinkedMap *_lru;
dispatch_queue_t _queue; // 用于釋放對象
特點:
訪問key,也會計算在LRU里面
添加key-value戚啥,先添加node奋单,再修剪cost,count
進入background猫十,內存警告览濒。你都可以自定義操作。
-
修剪:每5s做一次裁剪拖云。 清除超過限定的對象贷笛。
- 依據(jù):cost,count宙项,age(子線程中完成)
Nothing
總結:
YYMemoryCache是一個包裝了字典的乏苦,雙向鏈表的對象。
支持LRU。
依據(jù)cost, count , age來裁剪超載對象汇荐。(因為LRU的關系洞就,都從尾部開始裁)
支持內存警告,進入后臺時的自定義操作掀淘。
YYKVStorage
數(shù)據(jù)庫名詞解釋:
blob // (binary large object) 二進制大對象旬蟋。可以是一張圖片或一個聲音文件革娄。
File:
/path/
/manifest.sqlite
/manifest.sqlite-shm
/manifest.sqlite-wal
/data/
/e10adc3949ba59abbe56e057f20f883e
/e10adc3949ba59abbe56e057f20f883e
/trash/
/unused_file_or_folder
SQL:
create table if not exists manifest (
key text, // 傳值獲取
filename text, // 傳值獲取
size integer, // 計算文件獲取
inline_data blob, // 如果文件名length=0倾贰,此處插入文件。
奇怪的設定拦惋。相當于把本來存在數(shù)據(jù)庫外的文件匆浙,存在了數(shù)據(jù)庫里面。
modification_time integer, // 最后修改時間
last_access_time integer, // 最后訪問時間
extended_data blob, // 傳值獲取
primary key(key)
);
create index if not exists last_access_time_idx on manifest(last_access_time);
YYDiskCache
YYKVStorage *_kv;
dispatch_semaphore_t _lock;
dispatch_queue_t _queue; // 并發(fā)queue
_freeDiskSpaceLimit // 占用空間極限 0就是沒有限制
_countLimit | _costLimit | _ageLimit
TrimInterval = 60 // 修剪上面limit的intv
YYCache
存儲
-
先存內存
- YYMemoryCache 進行存儲
-
再存disk
-
YYDiskCache save kv
- 序列化對象
- 依據(jù)value大屑芗伞(默認20k)吞彤,選擇存儲方式
- YYKVStorage save kv
-
獲取
從YYMemoryCache中獲取
-
如果內存沒有,從本地獲取叹放。
- 從kv獲取
- 反序列化(可能需要拼裝上extData)
- 返回對象(同時緩存到YYMemoryCache饰恕,方便下次獲取)
細節(jié)
setObject的 obj 都遵循NSCoding協(xié)議
修剪:Disk定期修剪是60s井仰,Memory是5s埋嵌。
疑惑
mmap 熱數(shù)據(jù)的文件不要超過物理內存大小,不然 mmap 會導致內存交換嚴重降低性能啥意思俱恶?