iOS 緩存

一、為什么使用緩存

緩存的目的是以空間換時間。

出于優化考慮:服務器壓力、用戶體驗、用戶流量等;

出于功能考慮:離線存儲、微信會話列表、新聞列表等;

重度使用緩存的 APP:微信、微博等。

二、iOS 上的緩存框架

NSCache、PINCache、YYCache、SDWebImage(分析 SDImageCache 部分)

1、NSCache

蘋果提供的一個簡單的內存緩存;

類似 NSDictionary 一個可變的集合;

提供了可設置緩存大小與內存大小限制的方式;

保證了處理的數據的線程安全性;

內存警告時自動清理部分緩存數據

NSCache API

2、PINCache

PINCache 項目是在 Tumblr 宣布不再維護 TMCache 后,由 Pinterest 維護和改進的基于 TMCache 的一個內存緩存,修復了 TMCache 存在的性能和死鎖問題。

3、YYCache

YYCache 是國內開發者 ibireme 開源的一個線程安全的高性能緩存組件。

4、SDWebImage

SDWebImage 框架通過給 UIImageView 和 UIButton 添加分類,實現了一個異步下載圖片并且支持緩存的功能。整個框架的接口簡潔,分工明確。

三、線程安全

這些緩存框架都是線程安全的。

多線程操作共享數據不會出現意想不到的結果就是線程安全的,否則則是不安全的。多個線程同時訪問或讀取同一共享數據,每個線程的讀到的數據是一樣的,則不存在線程不安全。如果多個線程對同一資源進行讀寫操作,那么每個線程讀到的結果不可預料,線程是不安全的。

接下來:

1、iOS 中有哪些方法保證線程安全;

2、這些緩存框架是如何保證線程安全的。

四、iOS 開發中的鎖

1、OSSPinLock

2、dispatch_semaphore

3、pthread_mutex ?pthread_mutex(recursive) ?NSRecursiveLock

4、NSLock

5、NSCondition ?NSConditionLock

6、@synchronized

理解iOS開發中的鎖

鎖的性能

YYCache 和 PINCache 在內存緩存使用的是 pthread_mutex,在磁盤緩存使用的是Semaphone。 SDWebImage 在內存緩存使用的是 NSCache,本身就是線程安全的。在磁盤緩存使用串行隊列來保證線程安全。

保證線程安全的方式

五、緩存

1、緩存的讀取

緩存讀取的邏輯大致為:

先訪問內存緩存,再訪問磁盤緩存(寫入、讀取、查詢、刪除);

讀取緩存時,如果在內存緩存中無法獲取對應的緩存,則會去磁盤緩存中尋找。如果在磁盤緩存中找到了對應的緩存,則會將該對象再次寫入內存緩存中,保證下一次嘗試獲取同一緩存時能夠在內存中就能返回,提高速度。

2、二級緩存

MemoryCache

PINMemoryCache 通過維護一個 dic 記錄 object 最后一次訪問的時間,通過排序來實現 LRU;

YYMemoryCache 緩存內部通過雙向鏈表和 NSDictionary 實現 LRU 淘汰算法;

SDImageCache 緩存使用的是 NSCache。

DiskCache

PINDiskCache 和 SDImageCache 是基于文件系統的;

YYDiskCache 采用了 SQLite&文件系統實現。

3、SDWebImage

SDWebImage流程圖

SDImageCache 默認圖片清理時間為一周。

SDImageCache 緩存的寫入:

1、將圖片緩存在內存中;

2、判斷圖片格式是 png 或 jpeg,將圖片轉化為 NSData 數據;

3、如果是在 mac_os 系統中,直接將圖片轉化為 NSBitmapImageRep 數據;

4、獲取圖片的存儲路徑,其中圖片的文件名通過傳入的 key 經過 md5 加密后獲得的;

5、將圖片存儲在磁盤中。

SDImageCache 緩存的刪除:

1、獲取磁盤中圖片的最后修改日期;

2、根據日期將圖片進行分類,將超過最長存放時間的文件存儲在刪除數組中,其他的文件信息存儲在另一個 dic 中,并計算除去要刪除的文件之外的文件大小;

3、根據刪除數組中的文件路徑,將對應的文件刪除;

4、判斷剩下的文件大小是否超過用戶現在的最大容量;

5、如果超過,則將剩余文件按修改時間進行升序排列,刪除修改時間最早的文件,直到剩余文件大小小于最大磁盤容量。

清理時機:

系統內存不足時,會將內存中所有的圖片緩存刪除;

當系統進入后臺時,會對磁盤中的文件數據進行清理;

當收到程序關閉通知時,會對磁盤中的文件數據進行清理。

4、PINCache

PINCache 是線程安全的鍵值對緩存框架,用于緩存一些臨時數據或需要頻繁加載的數據。

類圖

PINCache 除了可以按鍵取值、按鍵存值、按鍵刪除值之外,還可以移除某個日期之外的緩存數據、刪除所有緩存、限制緩存大小。

PINCacheAPI

PINMemoryCache:

維護了三個 dic,分別為_dictionary、_dates、_costs,字典的 key 相同,value 分別為對象、最后訪問日期、大小。

清理緩存:

內存警告和進入后臺時,默認自動清除所有的內存緩存。

PINDiskCache

PINDiskCache 以文件形式存儲緩存,在內存中維護了兩個 ?dic分別為 _dates、_sizes,分別存儲了文件的最后編輯時間和文件大小。

在初始化時子線程遍歷硬盤緩存初始化這兩個值,開發中可以根據業務邏輯調用api刪除硬盤緩存。

支持清理的維度:age、byte。

5、YYCache

YYCache:提供了最外層的接口,調用了 YYmemoryCache 和 YYDiskCache 的相關方法;

YYMemoryCache:負責處理容量小,相對高速的內存緩存。線程安全,支持手動和自動清理緩存等功能;

_YYLinkedMap:YYMemoryCache 使用的雙向鏈表類;

_YYLinkedMapNode:是 _YYLinkedMap 使用的節點類;

YYDiskCache:負責處理容量大,相對低速的磁盤緩存。線程安全,支持異步操作,自動和手動清理緩存等功能;

YYKVStorage:YYDiskCache 的底層實現類,用于管理磁盤緩存;

YYKVStorageItem:內置在 YYKVStorage 中,是 YYKVStorage 內部用于封裝某個緩存的類。

API

YYMemoryCache:

將需要緩存的對象與傳入的 key 關聯起來,類似于 NSCache。

不同于 NSCache 的是,它的內部有:

緩存淘汰算法:LRU 算法來淘汰使用頻率較低的緩存;

緩存清理策略:三個維度分別為 count(緩存數量)、cost(開銷)、age(距上一次的訪問時間)。可根據不同的需求清理某一維度超標的緩存。

無論從哪一維度清理緩存,都是從使用頻率最低的那個緩存開始清理。

在 YYMemoryCache 中,使用了雙向鏈表來保存這些緩存:

當寫入一個新的緩存時,要把這個緩存節點放到鏈表頭部,并且原鏈表頭部的緩存節點要變成現在鏈表的第二個節點;

當訪問一個已有的緩存時,要把這個緩存節點移動到鏈表的頭部,原位置兩側的緩存接上,原頭部節點變為第二個;

(根據清理維度)自動清理緩存時,要從鏈表的最后端逐個清理。

清理緩存:

內存警告和進入后臺時,默認自動清除所有的內存緩存。

YYDiskCache:

與第一級緩存相同點是:

都具有查詢、寫入、讀取、刪除緩存的接口;

不直接操作緩存,通過另一個類(YYKVStorage)來操作;

使用 LRU 算法來清理緩存;

支持 cost、count、age 三個維度清理不符合標準的緩存。

不同點是:

1、根據緩存數據的大小來采取不同的形式的緩存:

數據庫 sqlite:針對小容量緩存,緩存的 data 和元數據都保存在數據庫里;

文件+數據庫形式:針對大容量緩存,緩存的 data 寫在文件系統中,其元數據保存在數據庫中。

2、除了 cost、count、age 三個維度,還添加了一個磁盤容量的維度。

六、緩存框架的選型

由圖可見:

1、YYMemoryCache 的性能不錯,僅次于 NSDictory+OSSpinLock;

2、NSCache 的寫入性能較差。讀寫性能不錯;

3、PINMemoryCache 的讀寫性能還可以,但讀取速度差于 NSCache;


由圖可見:

1、存取小數據時(NSNumber),YYDiskCache的性能遠遠高于基于文件存儲的庫;

2、較大數據的存取性能比較接近,但得益于 SQLite 存儲的元數據,YYDiskCache 實現了 LRU 淘汰算法、更快的數據統計,更多的容量控制選項。

總結

1、選擇合適的線程鎖;

2、選擇合適的數據結構;

3、選擇合適的線程來操作不同的任務;

4、選擇合適的存儲方式;

5、選擇底層的類;

6、變量、方法的命名以及接口的設計。

ppt:https://github.com/yuetianlu/cache_ppt

參考:

https://blog.ibireme.com/2015/10/26/yycache/

https://juejin.im/post/5a657a946fb9a01cb64ee761

https://juejin.im/post/5a4080d16fb9a0451969d0aa

https://www.cnblogs.com/fengmin/p/5318782.html

https://bestswifter.com/ios-lock/

http://www.cocoachina.com/ios/20171218/21570.html

https://blog.csdn.net/u012834750/article/details/69398216

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,578評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,701評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,691評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,974評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,694評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,026評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,015評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,193評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,719評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,442評論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,668評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,151評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,846評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,255評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,592評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,394評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,635評論 2 380

推薦閱讀更多精彩內容