簡稱SP,使用鍵值對的形式保存原始類型的數據,默認以XML格式的文件來存儲這些數據java
因爲咱們目前使用的SP方案,咱們的痛點,性能差,和ANR問題,考慮換一種數據存儲方案,首先咱們的數據存儲的場景並非複雜數據類型,量上也不是太大,因此優先考慮的就是MMKV,爲了更清楚的瞭解MMKV的優缺點,因此對比參考下android
名稱 | MMKV | Realm | WCDB | Room |
---|---|---|---|---|
方案 | mmap | nosql | SQLCipher | SQLite |
版本 | 1.0.24 | 6.0.2 | 1.0.8 | 2.2.3 |
size | 0.15mb | 1.5mb | 0.7mb | 0.05mb |
遷移 | 從SP遷移方便 | 從SQLite遷移方便 | ||
場景 | 替換SP | 替換SQLite | 替換SQLite | 替換SQLite |
注: size 爲armeabi-v7a架構下打包增量大小
mmkv包含lib_c++shared庫的size爲0.3mbc++
初始化 | MMKV | SP | Realm | Room | WCDB |
---|---|---|---|---|---|
耗時 | 30ms | 4ms | 60ms | 15ms | 80ms |
內存 | 1mb | 約1mb | 約2mb | 1mb | 2mb |
cpu峯值 | 16% | 20% | 18% | 15% | 15% |
SP | 執行次數 | 寫入耗時 | 讀取耗時 | 數據文件 |
---|---|---|---|---|
字符串 | 200 | 51ms | 4ms | 8kb |
字符串 | 1000 | 171ms | 6ms | 42kb |
Java實體 | 1000 | 220ms | 87ms | 172kb |
MMKV | 執行次數 | 寫入耗時 | 讀取耗時 | 數據文件 |
---|---|---|---|---|
字符串 | 200 | 8ms | 5ms | 4kb |
字符串 | 1000 | 20ms | 9ms | 16kb |
Java實體 | 1000 | 117ms | 93ms | 128kb |
Realm | 執行次數 | 寫入耗時 | 讀取耗時 | 數據文件 |
---|---|---|---|---|
字符串 | 200 | 229ms | 74ms | 32kb |
字符串 | 1000 | 606ms | 122ms | 288kb |
Java實體 | 1000 | 760ms | 130ms | 576kb |
Room | 執行次數 | 寫入耗時 | 讀取耗時 | 數據文件 |
---|---|---|---|---|
字符串 | 200 | 636ms | 160ms | 32kb |
字符串 | 1000 | 1350ms | 475ms | 48kb |
Java實體 | 1000 | 1298ms | 432ms | 68kb |
wcdb | 執行次數 | 寫入耗時 | 讀取耗時 | 數據文件 |
---|---|---|---|---|
字符串 | 200 | 636ms | 160ms | 32kb |
字符串 | 1000 | 1350ms | 475ms | 48kb |
Java實體 | 1000 | 1298ms | 432ms | 68kb |
內存消耗 | MMKV | SP |
---|---|---|
初始化 + 查詢1k條 | 1.7mb | 1.2mb |
初始化 + 查詢1w條 | 3.6mb | 2.8mb |
初始化 + 查詢5w條 | 10.7mb(文件8mb) | 8.5mb(文件8.6mb) |
字符串數據:含有隨機數的10個字節
運行手機:華爲 Mate10
執行線程:子線程
統計方式:取3次平均值
內存消耗:業務代碼讀取對應數據後釋放本地對象後的內存增量
因爲序列化反序列化會有緩存,Java實體
SP寫入爲apply異步方式
Realm、WCDB、Room 的插入操做均爲單條插入
MMKV、SP 讀取和寫入Java實體對象數據時間包含實體類序列化和反序列化時間,不過因爲序列化反序列化會有緩存,時間會稍偏小git
protobuf
存儲,SP使用xml
。protobuf
相比xml
來講性能更好,體積也會減少,可是真實存儲空間來看,mmkv的擴容機制(在空間不足時會申請一倍的空間)可能會致使實際使用空間變大,相比較SP的佔用的存儲空間就是真實的數據大小。MMKV 經過 mmap 內存映射文件,提供一段可供隨時寫入的內存塊,App 只管往裏面寫數據,由操做系統負責將內存回寫到文件,沒必要擔憂 crash 致使數據丟失。而SP則 MMKV 是一個跨平臺的解決方案,寫入性能相比sp有很大提高,適用於須要一個通用的 key-value 存儲組件,有跨進程訪問需求,尤爲是對如今sp存儲方案的不滿的同窗,mmkv同時支持了sp的遷移支持,基本上不用調整太多的代碼,遷移事項下面會詳述。github
Realm做爲一款移動端的NoSQL框架,官方定位就是替代SQLite等關係型數據庫,跨平臺,性能優秀,有可視化的查看工具。不足也比較明顯,不管是集成包size仍是數據文件都有點大。另外Realm要求當前Bean對象必須直接繼承RealmObject,侵入性很是強。有線程限制,不能跨線程使用數據對象。另外我在寫測試demo的時候發現了一個坑,若是一個線程查詢出列表後,另外一個線程再去增長或刪除會使得本地數據文件產生備份,致使數據庫文件急速增加,達到幾百MB,而且不會自動清理,官方對這個也有說明:sql
WCDB是一個高效、完整、易用的移動數據庫框架,基於SQLCipher,支持iOS, macOS和Android數據庫
Room並非一個數據庫,他是在 SQLiteo 的基礎上提供了一個抽象層,讓用戶可以在充分利用 SQLite 的強大功能的同時,獲享更強健的數據庫訪問機制。並保留了靈活的接口適配層。目前WCDB已經支持接入Room:github.com/Tencent/wcd…緩存
想嘗試的同窗能夠試試 ObjectBox,這個也是GreenDao做者的另外一力做,聽說性能比Realm還要好,因爲本次是對老項目中的SP存儲方案選型替換,暫時先不對比ObjectBox了,後續有時間了完善下相關對比記錄,有幾篇文章你們能夠參考
notes.devlabs.bg/realm-objec…
chejdj.github.io/android/201…安全
總結下吧,sp 和 mmkv 都是本身有一分內存級別的緩存,因此查詢很是快,可是若是數據量過大,會形成內存溢出,mmkv官方也對這點有說明,不要超過100mb,其實對正常的數據來講,確定到不了這個限制,若是30mb以上的數據,都要考慮使用數據庫類型的存儲了,上面測試數據對於數據庫類型的存儲不太公平,主要針對單次頻繁插入查詢的使用場景,數據庫使用場景通常會多條數據經過事務批量寫入,查詢的時候也會查詢一類數據集合。綜上所述,目前採用mmkv替換sp的實現仍是有很大收益的,性能和跨進程上都有優點,而且避免了sp的ANR問題,體積上也沒有加大多少;若是數據庫方案,建議採用Room,或者在嘗試下上面說的可是沒在本次測試對比的objectbox。感受要注意的挺多,不過零零散散只整理了這麼點...架構
遷移官方文檔:github.com/Tencent/MMK…
MMKV 不支持 Serializable,可是能夠考慮把 Serializable 的 java對象 轉換成 byte 存入MMKV
MMKV初始存儲空間4kb,不足的時擴容最少是一倍,而且爲了效率在移除key value
不會減少磁盤存儲空間,官方提供了kv.trim
方法去縮減磁盤存儲空間,不過官方建議調用時機是有大量移除操做的時候執行,通常無需考慮存儲文件增加問題,但這個時機很差掌握,不過感受能夠按期清理一次
SP#getAll
SP#registerOnSharedPreferenceChangeListener
等方法不支持,調用會拋出運行時異常,須要注意。getAll
由於擦除了類型,因此不支持,感受這是mmkv相對較弱的地方,也爲之後遷移其餘存儲方案增長了成本
一些 Android 設備(API level 19)在安裝/更新 APK 時可能出錯, 致使 libmmkv.so 找不到。而後就會遇到 java.lang.UnsatisfiedLinkError 之類的 crash。有個開源庫 ReLinker 專門解決這個問題,不過如今還在支持19的應用應該很少了
對於歷史項目SP數據可能比較龐大,這樣直接使用官方提供的mmkv#importFromSharedPreferences
方法直接對一個文件進行遷移,會形成耗時過長的問題,目前Demo測試數據:測試機型華爲Mate10,一個4MB左右的SP的文件遷移到MMKV大約耗時80ms左右,到了線上應該還會更長,因此爲了不初次使用卡住的體驗問題,這裏提供兩個解決思路:1.在使用前統一遷移,而且給予用戶一個遷移數據的提示;2.在初次使用的時候後臺靜默遷移。目前咱們使用的是第二種思路,這種狀況須要保證數據的準確性,若是有同窗有興趣能夠留言探討
官方和網上各類對比測試文章