MMKV 組件現(xiàn)在開源了

本文轉(zhuǎn)自微信開發(fā)團(tuán)隊(duì)凌國(guó)的分享墙懂。原文

MMKV 是基于 mmap 內(nèi)存映射的移動(dòng)端通用 key-value 組件弃榨,底層序列化/反序列化使用 protobuf 實(shí)現(xiàn)挚赊,性能高抓艳,穩(wěn)定性強(qiáng)。從 2015 年中至今遭笋,在 iOS 微信上使用已有近 3 年坝冕,其性能和穩(wěn)定性經(jīng)過(guò)了時(shí)間的驗(yàn)證徒探。近期已移植到 Android 平臺(tái)瓦呼。在騰訊內(nèi)部開源半年之后,得到公司內(nèi)部團(tuán)隊(duì)的廣泛應(yīng)用和一致好評(píng)。現(xiàn)在一并對(duì)外開源:

https://github.com/tencent/mmkv

歡迎 Star央串、提 Issue 和 PR磨澡。

MMKV 源起

在微信客戶端的日常運(yùn)營(yíng)中,時(shí)不時(shí)就會(huì)爆發(fā)特殊文字引起系統(tǒng)的 crash质和,參考文章稳摄,文章里面設(shè)計(jì)的技術(shù)方案是在關(guān)鍵代碼前后進(jìn)行計(jì)數(shù)器的加減,通過(guò)檢查計(jì)數(shù)器的異常饲宿,來(lái)發(fā)現(xiàn)引起閃退的異常文字厦酬。在會(huì)話列表、會(huì)話界面等有大量 cell 的地方瘫想,希望新加的計(jì)時(shí)器不會(huì)影響滑動(dòng)性能仗阅;另外這些計(jì)數(shù)器還要永久存儲(chǔ)下來(lái)——因?yàn)殚W退隨時(shí)可能發(fā)生。這就需要一個(gè)性能非常高的通用 key-value 存儲(chǔ)組件国夜,我們考察了 SharedPreferences减噪、NSUserDefaults、SQLite 等常見(jiàn)組件车吹,發(fā)現(xiàn)都沒(méi)能滿足如此苛刻的性能要求筹裕。考慮到這個(gè)防 crash 方案最主要的訴求還是實(shí)時(shí)寫入窄驹,而 mmap 內(nèi)存映射文件剛好滿足這種需求朝卒,我們嘗試通過(guò)它來(lái)實(shí)現(xiàn)一套 key-value 組件。

MMKV 原理

  • 內(nèi)存準(zhǔn)備
    通過(guò) mmap 內(nèi)存映射文件乐埠,提供一段可供隨時(shí)寫入的內(nèi)存塊扎运,App 只管往里面寫數(shù)據(jù),由操作系統(tǒng)負(fù)責(zé)將內(nèi)存回寫到文件饮戳,不必?fù)?dān)心 crash 導(dǎo)致數(shù)據(jù)丟失豪治。

  • 數(shù)據(jù)組織
    數(shù)據(jù)序列化方面我們選用 protobuf 協(xié)議,pb 在性能和空間占用上都有不錯(cuò)的表現(xiàn)扯罐。

  • 寫入優(yōu)化
    考慮到主要使用場(chǎng)景是頻繁地進(jìn)行寫入更新负拟,我們需要有增量更新的能力。我們考慮將增量 kv 對(duì)象序列化后歹河,append 到內(nèi)存末尾掩浙。

  • 空間增長(zhǎng)
    使用 append 實(shí)現(xiàn)增量更新帶來(lái)了一個(gè)新的問(wèn)題,就是不斷 append 的話秸歧,文件大小會(huì)增長(zhǎng)得不可控厨姚。我們需要在性能和空間上做個(gè)折中。

更詳細(xì)的設(shè)計(jì)原理參考前文 《MMKV——iOS 下基于 mmap 的高性能通用 key-value 組件》键菱。

MMKV for Android 特有功能

我們不是簡(jiǎn)簡(jiǎn)單單地照搬 iOS 的實(shí)現(xiàn)谬墙,在遷移到 Android 的過(guò)程中,深入分析了 Android 平臺(tái)現(xiàn)有 kv 組件的痛點(diǎn),在原有功能基礎(chǔ)上拭抬,開發(fā)了 Android 特有的功能部默。

  • 多進(jìn)程訪問(wèn)
    通過(guò)與 Android 開發(fā)同學(xué)的溝通,了解到系統(tǒng)自帶的 SharedPreferences 對(duì)多進(jìn)程的支持不好≡旎ⅲ現(xiàn)有基于 ContentProvider 封裝的實(shí)現(xiàn)傅蹂,雖然多進(jìn)程是支持了,但是性能低下算凿,經(jīng)常導(dǎo)致 ANR份蝴。考慮到 mmap 共享內(nèi)存本質(zhì)上的多進(jìn)程共享的氓轰,我們?cè)谶@個(gè)基礎(chǔ)上搞乏,深入挖掘了 Android 系統(tǒng)的能力,提供了可能是業(yè)界最高效的多進(jìn)程數(shù)據(jù)共享組件戒努。具體實(shí)現(xiàn)原理我們中秋節(jié)后分享请敦,心急的同學(xué)可以前往 GitHub 查看源碼和 wiki 文檔。

  • 匿名內(nèi)存
    在多進(jìn)程共享的基礎(chǔ)上储玫,考慮到某些敏感數(shù)據(jù)(例如密碼)需要進(jìn)程間共享侍筛,但是不方便落地存儲(chǔ)到文件上,直接用 mmap 不合適撒穷。我們了解到 Android 系統(tǒng)提供了 Ashmem 匿名共享內(nèi)存的能力匣椰,發(fā)現(xiàn)它在進(jìn)程退出后就會(huì)消失,不會(huì)落地到文件上端礼,非常適合這個(gè)場(chǎng)景禽笑。我們很愉快地提供了 Ashmem MMKV 的功能。

  • 數(shù)據(jù)加密
    不像 iOS 提供了硬件層級(jí)的加密機(jī)制蛤奥,在 Android 環(huán)境里佳镜,數(shù)據(jù)加密是非常必須的。MMKV 使用了 AES CFB-128 算法來(lái)加密/解密凡桥。我們選擇 CFB 而不是常見(jiàn)的 CBC 算法蟀伸,主要是因?yàn)?MMKV 使用 append-only 實(shí)現(xiàn)插入/更新操作,流式加密算法更加合適缅刽。事實(shí)上這個(gè)功能也回饋到了 iOS 版啊掏,所以現(xiàn)在兩個(gè)系統(tǒng)的 MMKV 都有加密功能。

MMKV 使用

iOS 的使用在前文已經(jīng)陳述衰猛,這里簡(jiǎn)單介紹一下 Android 的用法迟蜜。

Android 快速上手

MMKV 已托管到 bintray(JCenter),可以直接使用啡省。在 App 的 build.gradle 里加上依賴:

MMKV 的使用非常簡(jiǎn)單娜睛,所有變更立馬生效髓霞,無(wú)需調(diào)用 syncapply微姊。 在 App 啟動(dòng)時(shí)初始化 MMKV酸茴,設(shè)定 MMKV 的根目錄(files/mmkv/)分预,例如在 MainActivity 里:

MMKV 提供一個(gè)全局的實(shí)例兢交,可以直接使用:

如果不同業(yè)務(wù)需要區(qū)別存儲(chǔ),也可以單獨(dú)創(chuàng)建自己的實(shí)例:

SharedPreferences 遷移

  • MMKV 提供了 importFromSharedPreferences() 函數(shù)笼痹,可以比較方便地遷移數(shù)據(jù)過(guò)來(lái)配喳。

  • MMKV 還額外實(shí)現(xiàn)了一遍 SharedPreferences、SharedPreferences.Editor 這兩個(gè) interface凳干,在遷移的時(shí)候只需兩三行代碼即可晴裹,其他 CRUD 操作代碼都不用改。

更詳細(xì)的用法可以參看 GitHub 上的 wiki 文檔救赐。

MMKV 性能

iOS 性能對(duì)比

我們將 MMKV 和 NSUserDefaults 進(jìn)行對(duì)比涧团,重復(fù)讀寫操作 1w 次。相關(guān)測(cè)試代碼在 iOS/MMKVDemo/MMKVDemo/经磅,結(jié)果見(jiàn)如下圖表泌绣。

image

(測(cè)試機(jī)器是 iPhone X 256 G,iOS 12 beta 2预厌,每組操作重復(fù) 1w 次阿迈,時(shí)間單位是 ms。)

可見(jiàn)轧叽,MMKV 在寫入性能上遠(yuǎn)遠(yuǎn)超越 NSUserDefaults苗沧,在讀取性能上也有相近或超越的表現(xiàn)。

Android 性能對(duì)比

我們將 MMKV 和 SharedPreferences炭晒、SQLite 進(jìn)行對(duì)比, 重復(fù)讀寫操作 1k 次待逞。相關(guān)測(cè)試代碼在 Android/MMKV/mmkvdemo/。結(jié)果如下圖表网严。

  • 單進(jìn)程性能
    可見(jiàn)飒焦,MMKV 在寫入性能上遠(yuǎn)遠(yuǎn)超越 SharedPreferences & SQLite,在讀取性能上也有相近或超越的表現(xiàn)屿笼。

    image

    (測(cè)試機(jī)器是 Pixel 2 XL 64G牺荠,Android 8.1,每組操作重復(fù) 1k 次驴一,時(shí)間單位是 ms休雌。)

  • 多進(jìn)程性能
    可見(jiàn),MMKV 無(wú)論是在寫入性能還是在讀取性能肝断,都遠(yuǎn)遠(yuǎn)超越 MultiProcessSharedPreferences & SQLite & SQLite杈曲, MMKV 在 Android 多進(jìn)程 key-value 存儲(chǔ)組件上是不二之選驰凛。

    image

    (測(cè)試機(jī)器是 Pixel 2 XL 64G,Android 8.1担扑,每組操作重復(fù) 1k 次恰响,時(shí)間單位是 ms。)

點(diǎn)擊原文直接訪問(wèn) GitHub 源碼涌献。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末胚宦,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子燕垃,更是在濱河造成了極大的恐慌枢劝,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,470評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件卜壕,死亡現(xiàn)場(chǎng)離奇詭異您旁,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)轴捎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門鹤盒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人侦副,你說(shuō)我怎么就攤上這事侦锯。” “怎么了跃洛?”我有些...
    開封第一講書人閱讀 162,577評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵率触,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我汇竭,道長(zhǎng)葱蝗,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,176評(píng)論 1 292
  • 正文 為了忘掉前任细燎,我火速辦了婚禮两曼,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘玻驻。我一直安慰自己悼凑,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評(píng)論 6 388
  • 文/花漫 我一把揭開白布璧瞬。 她就那樣靜靜地躺著户辫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪嗤锉。 梳的紋絲不亂的頭發(fā)上渔欢,一...
    開封第一講書人閱讀 51,155評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音瘟忱,去河邊找鬼奥额。 笑死苫幢,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的垫挨。 我是一名探鬼主播韩肝,決...
    沈念sama閱讀 40,041評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼九榔!你這毒婦竟也來(lái)了哀峻?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,903評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤帚屉,失蹤者是張志新(化名)和其女友劉穎谜诫,沒(méi)想到半個(gè)月后漾峡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體攻旦,經(jīng)...
    沈念sama閱讀 45,319評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評(píng)論 2 332
  • 正文 我和宋清朗相戀三年生逸,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了牢屋。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,703評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡槽袄,死狀恐怖烙无,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情遍尺,我是刑警寧澤截酷,帶...
    沈念sama閱讀 35,417評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站乾戏,受9級(jí)特大地震影響迂苛,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜鼓择,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評(píng)論 3 325
  • 文/蒙蒙 一三幻、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧呐能,春花似錦念搬、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至偎漫,卻和暖如春爷恳,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背骑丸。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工舌仍, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留妒貌,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,711評(píng)論 2 368
  • 正文 我出身青樓铸豁,卻偏偏與公主長(zhǎng)得像灌曙,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子节芥,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,072評(píng)論 25 707
  • 用兩張圖告訴你在刺,為什么你的 App 會(huì)卡頓? - Android - 掘金 Cover 有什么料? 從這篇文章中你...
    hw1212閱讀 12,714評(píng)論 2 59
  • 我和寫作 小時(shí)候在新浪寫過(guò)一點(diǎn)博客头镊,當(dāng)然都是瞎寫蚣驼,寫點(diǎn)什么小說(shuō)啥的。雖然寫的很爛相艇,但是還有點(diǎn)喜歡手指在鍵盤上跳舞的...
    閉眼唱歌閱讀 451評(píng)論 1 1
  • 文/藍(lán)子辰 時(shí)間過(guò)得非常得快,跟著無(wú)戒老師學(xué)習(xí)寫作已經(jīng)21天咙轩。 我從6月12日開始日更打卡获讳,到今天7月2日止,已經(jīng)...
    藍(lán)子辰閱讀 927評(píng)論 23 33
  • 喜歡是開始, 合適是一生钾菊, 懂得是輕松帅矗。 每一份情,都來(lái)自喜歡结缚;每一份情损晤,都來(lái)自欣賞。所以...
    南天九茴閱讀 356評(píng)論 0 1