MMKV的簡單實用一

MMKV 是基於 mmap 內存映射的移動端通用 key-value 組件,底層序列化/反序列化使用 protobuf 實現,性能高,穩定性強。從 2015 年中至今在微信上使用,其性能和穩定性經過了時間的驗證。近期也已移植到 Android / macOS / Windows 平臺,一併開源。

MMKV官方鏈接

MMKV 源起
在微信客戶端的日常運營中,時不時就會爆發特殊文字引起系統的 crash,參考文章,文章裏面設計的技術方案是在關鍵代碼前後進行計數器的加減,通過檢查計數器的異常,來發現引起閃退的異常文字。在會話列表、會話界面等有大量 cell 的地方,希望新加的計時器不會影響滑動性能;另外這些計數器還要永久存儲下來——因爲閃退隨時可能發生。這就需要一個性能非常高的通用 key-value 存儲組件,我們考察了 SharedPreferences、NSUserDefaults、SQLite 等常見組件,發現都沒能滿足如此苛刻的性能要求。考慮到這個防 crash 方案最主要的訴求還是實時寫入,而 mmap 內存映射文件剛好滿足這種需求,我們嘗試通過它來實現一套 key-value 組件

MMKV 原理

  1. 內存準備
    通過 mmap 內存映射文件,提供一段可供隨時寫入的內存塊,App 只管往裏面寫數據,由操作系統負責將內存回寫到文件,不必擔心 crash 導致數據丟失。
  2. 數據組織
    數據序列化方面我們選用 protobuf 協議,pb 在性能和空間佔用上都有不錯的表現。
  3. 寫入優化
    考慮到主要使用場景是頻繁地進行寫入更新,我們需要有增量更新的能力。我們考慮將增量 kv 對象序列化後,append 到內存末尾。
  4. 空間增長
    使用 append 實現增量更新帶來了一個新的問題,就是不斷 append 的話,文件大小會增長得不可控。我們需要在性能和空間上做個折中。

優點

  1. 多進程訪問
    通過與 Android 開發同學的溝通,瞭解到系統自帶的 SharedPreferences 對多進程的支持不好。現有基於 ContentProvider 封裝的實現,雖然多進程是支持了,但是性能低下,經常導致 ANR。考慮到 mmap 共享內存本質上的多進程共享的,我們在這個基礎上,深入挖掘了 Android 系統的能力,提供了可能是業界最高效的多進程數據共享組件。具體實現原理我們中秋節後分享,心急的同學可以前往 GitHub 查看源碼和 wiki 文檔。

  2. 匿名內存
    在多進程共享的基礎上,考慮到某些敏感數據(例如密碼)需要進程間共享,但是不方便落地存儲到文件上,直接用 mmap 不合適。我們瞭解到 Android 系統提供了 Ashmem 匿名共享內存的能力,發現它在進程退出後就會消失,不會落地到文件上,非常適合這個場景。我們很愉快地提供了 Ashmem MMKV 的功能。

  3. 數據加密
    不像 iOS 提供了硬件層級的加密機制,在 Android 環境裏,數據加密是非常必須的。MMKV 使用了 AES CFB-128 算法來加密/解密。我們選擇 CFB 而不是常見的 CBC 算法,主要是因爲 MMKV 使用 append-only 實現插入/更新操作,流式加密算法更加合適。事實上這個功能也回饋到了 iOS 版,所以現在兩個系統的 MMKV 都有加密功能。

推薦使用 Maven:

dependencies {
    implementation 'com.tencent:mmkv:1.0.23'
    // replace "1.0.23" with any available version
}
   private MMKV kv = null;

   @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main)
        String rootDir = MMKV.initialize(this);
        kv = MMKV.defaultMMKV();
    }
   kv.encode("name","張三");
   kv.encode("boolean",false);
   kv.encode("int",132);
   boolean bValue = kv.decodeBool("boolean");
   Log.e("dobValue", "bValue bValue  Bool  " + bValue);
   String name = kv.decodeString("name");
   Log.e("dobValue", "bValue bValue  name " + name);
   int num = kv.decodeInt("int");
   Log.e("dobValue", "bValue bValue  num " + num);

參考資料:
MMKV——基於 mmap 的高性能通用 key-value 組件

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章