日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

sharedpreferences 重启不保存_MMKV为什么可以替换SharedPreferences

發布時間:2025/4/16 编程问答 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 sharedpreferences 重启不保存_MMKV为什么可以替换SharedPreferences 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

MMKV介紹

MMKV——基于 mmap 的高性能通用 key-value 組件,底層序列化/反序列化使用 protobuf 實現,性能高,穩定性強。
https://github.com/Tencent/MMKV/blob/master/readme_cn.md

MMKV 是基于 mmap 內存映射的移動端通用 key-value 組件,底層序列化/反序列化使用 protobuf 實現,性能高,穩定性強。
從 2015 年中至今,在 iOS 微信上使用已有近 3 年,其性能和穩定性經過了時間的驗證。
近期已移植到 Android 平臺。在騰訊內部開源半年之后,得到公司內部團隊的廣泛應用和一致好評。

通過 mmap 內存映射文件,提供一段可供隨時寫入的內存塊,App 只管往里面寫數據,
由操作系統負責將內存回寫到文件,不必擔心 crash 導致數據丟失。

XML、JSON 更注重數據結構化,關注人類可讀性和語義表達能力。
ProtoBuf 更注重數據序列化,關注效率、空間、速度,人類可讀性差,語義表達能力不足(為保證極致的效率,會舍棄一部分元信息)

MMKV特點

1.高性能

可以支持實時寫入

2.穩定性非常好
3.多進程訪問

通過與 Android 開發同學的溝通,了解到系統自帶的 SharedPreferences 對多進程的支持不好。
現有基于 ContentProvider 封裝的實現,雖然多進程是支持了,但是性能低下,經常導致 ANR。
考慮到 mmap 共享內存本質上的多進程共享的,我們在這個基礎上,深入挖掘了 Android 系統的能力,提供了可能是業界最高效的多進程數據共享組件。

4.匿名內存

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

5.數據加密

不像 iOS 提供了硬件層級的加密機制,在 Android 環境里,數據加密是非常必須的。
MMKV 使用了 AES CFB-128 算法來加密/解密。我們選擇 CFB 而不是常見的 CBC 算法,
主要是因為 MMKV 使用 append-only 實現插入/更新操作,流式加密算法更加合適。

6.數據有效性

考慮到文件系統、操作系統都有一定的不穩定性,我們另外增加了 crc 校驗,對無效數據進行甄別。

MMKV 原理

1.內存準備

通過 mmap 內存映射文件,提供一段可供隨時寫入的內存塊,App 只管往里面寫數據,由操作系統負責將內存回寫到文件,不必擔心 crash 導致數據丟失。

2.數據組織

數據序列化方面我們選用 protobuf 協議,pb 在性能和空間占用上都有不錯的表現。

3.寫入優化

考慮到主要使用場景是頻繁地進行寫入更新,我們需要有增量更新的能力。我們考慮將增量 kv 對象序列化后,append 到內存末尾。
這樣同一個 key 會有新舊若干份數據,最新的數據在最后;那么只需在程序啟動第一次打開 mmkv 時,不斷用后讀入的 value 替換之前的值,就可以保證數據是最新有效的。

4.空間增長

使用 append 實現增量更新帶來了一個新的問題,就是不斷 append 的話,文件大小會增長得不可控。我們需要在性能和空間上做個折中。
以內存 pagesize 為單位申請空間,在空間用盡之前都是 append 模式;當 append 到文件末尾時,進行文件重整、key 排重,嘗試序列化保存排重結果;
排重后空間還是不夠用的話,將文件擴大一倍,直到空間足夠。

5.數據有效性

考慮到文件系統、操作系統都有一定的不穩定性,我們另外增加了 crc 校驗,對無效數據進行甄別。

詳細的原理請參考:https://github.com/Tencent/MMKV/wiki/design

MMKV集成

1.依賴注入

在 App 模塊的 build.gradle 文件里添加:

dependencies {
implementation 'com.tencent:mmkv-static:1.2.2'
// replace "1.2.2" with any available version
}

Gradle 在編譯工程的時候會自動從 maven 倉庫下載 AAR 包。

MMKV 默認以靜態庫形式鏈接 libc++。這個庫如果動態鏈接,會額外占用 2MB 空間(解壓后)。如果你已經有其他庫引入了 libc++_shared.so,并且你確保他們的庫沒有版本兼容問題,你可以使用動態鏈接 libc++ 的 MMKV,以進一步減少安裝包大小:

dependencies {
implementation 'com.tencent:mmkv:1.2.2'
// replace "1.2.2" with any available version
}
2.初始化
// 設置初始化的根目錄
String dir = getFilesDir().getAbsolutePath() + "/mmkv_2";
String rootDir = MMKV.initialize(dir);
Log.i("MMKV", "mmkv root: " + rootDir);
3.獲取實例
// 獲取默認的全局實例
MMKV kv = MMKV.defaultMMKV();

// 根據業務區別存儲, 附帶一個自己的 ID
MMKV kv = MMKV.mmkvWithID("MyID");

// 多進程同步支持
MMKV kv = MMKV.mmkvWithID("MyID", MMKV.MULTI_PROCESS_MODE);
4.具體操作
// 添加/更新數據
kv.encode(key, value);

// 獲取數據
int tmp = kv.decodeInt(key);

// 刪除數據
kv.removeValueForKey(key);
5.SharedPreferences遷移
private void testImportSharedPreferences() {
MMKV mmkv = MMKV.mmkvWithID("myData");
SharedPreferences old_man = getSharedPreferences("myData", MODE_PRIVATE);
// 遷移舊數據
mmkv.importFromSharedPreferences(old_man);
// 清空舊數據
old_man.edit().clear().commit();
......
}

詳細的集成文檔請參考:https://github.com/Tencent/MMKV/wiki/android_setup_cn

性能測試

以下是 MMKV、SharedPreferences 和 SQLite 同步寫入 1000 條數據的測試結果

// MMKV
MMKV write int: loop[1000]: 12 ms
MMKV read int: loop[1000]: 3 ms

MMKV write String: loop[1000]: 7 ms
MMKV read String: loop[1000]: 4 ms

// SharedPreferences
SharedPreferences write int: loop[1000]: 119 ms
SharedPreferences read int: loop[1000]: 3 ms

SharedPreferences write String: loop[1000]: 187
SharedPreferences read String: loop[1000]: 2 ms

// SQLite
sqlite write int: loop[1000]: 101 ms
sqlite read int: loop[1000]: 136 ms

sqlite write String: loop[1000]: 29 ms
sqlite read String: loop[1000]: 93 ms

可以看到 MMKV 無論是對比 SP 還是 SQLite, 在性能上都有非常大的優勢, 官方提供的數據測試結果如下

1.單進程性能

可見,MMKV 在寫入性能上遠遠超越 SharedPreferences & SQLite,在讀取性能上也有相近或超越的表現。

2.多進程性能

可見,MMKV 無論是在寫入性能還是在讀取性能,都遠遠超越 MultiProcessSharedPreferences & SQLite & SQLite,
MMKV 在 Android 多進程 key-value 存儲組件上是不二之選。

核心原理

Linux的內存分用戶空間跟內核空間,同時頁表有也分兩類,用戶空間頁表跟內核空間頁表,每個進程有一個用戶空間頁表,但是系統只有一個內核空間頁表。
而Binder mmap的關鍵:更新用戶空間對應的頁表的同時也同步映射內核頁表,讓兩個頁表都指向同一塊地址。
這樣一來,數據只需要從A進程的用戶空間,直接拷貝到B所對應的內核空間,而B多對應的內核空間在B進程的用戶空間也有相應的映射,這樣就無需從內核拷貝到用戶空間了。

copy_from_user() //將數據從用戶空間拷貝到內核空間
copy_to_user() //將數據從內核空間拷貝到用戶空間

mmap VS 普通文件IO

1.普通文件IO

通過read/write系統調訪問,先在用戶空間分配一段buffer,然后,進入內核,將內容從磁盤讀取到內核緩沖,最后,拷貝到用戶進程空間,至少牽扯到兩次數據拷貝;
同時,多個進程同時訪問一個文件,每個進程都有一個副本,存在資源浪費的問題。

2.mmap

通過mmap來訪問文件,mmap()將文件直接映射到用戶空間,文件在mmap的時候,內存并未真正分配,
只有在第一次讀取/寫入的時候才會觸發,這個時候,會引發缺頁中斷,在處理缺頁中斷的時候,完成內存也分配,同時也完成文件數據的拷貝。
并且,修改用戶空間對應的頁表,完成到物理內存到用戶空間的映射,這種方式只存在一次數據拷貝,效率更高。
同時多進程間通過mmap共享文件數據的時候,僅需要一塊物理內存就夠了。

Android中使用mmap,可以通過RandomAccessFile與MappedByteBuffer來配合。
通過randomAccessFile.getChannel().map獲取到MappedByteBuffer。然后調用ByteBuffer的put方法添加數據。

RandomAccessFile randomAccessFile = new RandomAccessFile("path","rw");
MappedByteBuffer mappedByteBuffer= randomAccessFile.getChannel().map(FileChannel.MapMode.READ_WRITE,0, randomAccessFile.length());

mappedByteBuffer.putChar('c');
mappedByteBuffer.getChar();

總結

通過上面的分析, 我們對 MMKV 有了一個整體上的把控, 其具體的表現如下所示

項目評價描述
正確性支持多進程安全, 使用 mmap, 由操作系統保證數據回寫的正確性
時間開銷使用 mmap 實現, 減少了用戶空間數據到內核空間的拷貝
空間開銷使用 protocl buffer 存儲數據, 同樣的數據會比 xml 和 json 消耗空間小,使用的是數據追加到末尾的方式, 只有到達一定閾值之后才會觸發鍵值合并, 不合并之前會導致同一個 key 存在多份
安全使用 crc 校驗, 甄別文件系統和操作系統不穩定導致的異常數據
開發成本使用方式較為簡單
兼容性各個安卓版本都前后兼容

雖然 MMKV 一些場景下比 SP 稍慢(如: 首次實例化會進行數據的復寫剔除重復數據, 比 SP 稍慢, 查詢數據時存在 ProtocolBuffer 解碼, 比 SP 稍慢), 但其逆天的數據寫入速度、mmap Linux 內核保證數據的同步, 以及 ProtocolBuffer 編碼帶來的更小的本地存儲空間占用等都是非常棒的閃光點。

參考文獻:

https://www.jianshu.com/p/65334d245bc4

https://blog.csdn.net/gpf1320253667/article/details/91352887

https://github.com/Tencent/MMKV/releases

總結

以上是生活随笔為你收集整理的sharedpreferences 重启不保存_MMKV为什么可以替换SharedPreferences的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。