微信自用高效能通用key-value元件MMKV已開源!
1、MMKV簡介
騰訊微信團隊於2018年9月底宣佈開源 MMKV ,這是基於 mmap 記憶體對映的 key-value 元件,底層序列化/反序列化使用 protobuf 實現,主打高效能和穩定性。近期也已移植到 Android 平臺,一併對外開源。
MMKV 是基於 mmap 記憶體對映的 key-value 元件,底層序列化/反序列化使用 protobuf 實現,效能高,穩定性強。從 2015 年中至今,在 iOS 微信上使用已有近 3 年,其效能和穩定性經過了時間的驗證。近期也已移植到 Android 平臺,一併開源。
MMKV最新原始碼託管地址: ofollow,noindex">https://github.com/Tencent/MMKV
2、MMKV 源起
在微信客戶端的日常運營中,時不時就會爆發特殊文字引起系統的 crash(請參見文章:《微信團隊分享:iOS版微信是如何防止特殊字元導致的炸群、APP崩潰的? 》、《微信團隊分享:iOS版微信的高效能通用key-value元件技術實踐 》),文章裡面設計的技術方案是在關鍵程式碼前後進行計數器的加減,通過檢查計數器的異常,來發現引起閃退的異常文字。在會話列表、會話介面等有大量 cell 的地方,希望新加的計時器不會影響滑動效能;另外這些計數器還要永久儲存下來——因為閃退隨時可能發生。
這就需要一個性能非常高的通用 key-value 儲存元件,我們考察了 SharedPreferences、NSUserDefaults、SQLite 等常見元件,發現都沒能滿足如此苛刻的效能要求。考慮到這個防 crash 方案最主要的訴求還是實時寫入,而 mmap 記憶體對映檔案剛好滿足這種需求,我們嘗試通過它來實現一套 key-value 元件。
3、MMKV 原理
記憶體準備:
通過 mmap 記憶體對映檔案,提供一段可供隨時寫入的記憶體塊,App 只管往裡面寫資料,由作業系統負責將記憶體回寫到檔案,不必擔心 crash 導致資料丟失。
資料組織:
資料序列化方面我們選用 protobuf 協議,pb 在效能和空間佔用上都有不錯的表現。
寫入優化:
考慮到主要使用場景是頻繁地進行寫入更新,我們需要有增量更新的能力。我們考慮將增量 kv 物件序列化後,append 到記憶體末尾。
空間增長:
使用 append 實現增量更新帶來了一個新的問題,就是不斷 append 的話,檔案大小會增長得不可控。我們需要在效能和空間上做個折中。
更詳細的設計原理參考MMKV 原理 。
4、iOS 指南
安裝引入(推薦使用 CocoaPods):
安裝CocoaPods ;
開啟命令列,cd到你的專案工程目錄, 輸入pod repo update讓 CocoaPods 感知最新的 MMKV 版本;
開啟 Podfile, 新增pod 'MMKV'到你的 app target 裡面;
在命令列輸入pod install;
用 Xcode 開啟由 CocoaPods 自動生成的.xcworkspace檔案;
新增標頭檔案#import <MMKV/MMKV.h>,就可以愉快地開始你的 MMKV 之旅了。
更多安裝指引參考iOS Setup 。
快速上手:
MMKV 的使用非常簡單,無需任何配置,所有變更立馬生效,無需呼叫synchronize:
MMKV *mmkv = [MMKV defaultMMKV]; [mmkvsetBool:YESforKey:@"bool"];BOOL bValue = [mmkvgetBoolForKey:@"bool"]; [mmkvsetInt32:-1024forKey:@"int32"];int32_t iValue = [mmkvgetInt32ForKey:@"int32"]; [mmkvsetObject:@"hello, mmkv"forKey:@"string"];NSString *str = [mmkvgetObjectOfClass:NSString.classforKey:@"string"];
更詳細的使用教程參考iOS Tutorial 。
效能對比:
迴圈寫入隨機的int1w 次,我們有如下效能對比:
更詳細的效能對比參考iOS Benchmark 。
5、Android 指南
安裝引入:
推薦使用 Maven:
dependencies{implementation'com.tencent:mmkv:1.0.10'// replace"1.0.10"with any available version}
更多安裝指引參考Android Setup 。
快速上手:
MMKV 的使用非常簡單,所有變更立馬生效,無需呼叫sync、apply。 在 App 啟動時初始化 MMKV,設定 MMKV 的根目錄(files/mmkv/),例如在 MainActivity 裡:
protectedvoidonCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState); String rootDir = MMKV.initialize(this); System.out.println("mmkv root: "+ rootDir);//……}
MMKV 提供一個全域性的例項,可以直接使用:
importcom.tencent.mmkv.MMKV;//……MMKV kv = MMKV.defaultMMKV();kv.encode("bool",true);booleanbValue = kv.decodeBool("bool");kv.encode("int", Integer.MIN_VALUE);intiValue = kv.decodeInt("int");kv.encode("string","Hello from mmkv");String str = kv.decodeString("string");
MMKV 支援多程序訪問,更詳細的用法參考Android Tutorial 。
效能對比:
迴圈寫入隨機的int1k 次,我們有如下效能對比:
更詳細的效能對比參考Android Benchmark 。