基于 mmap 的高性能通用 key-value 组件, 底层序列化/反序列化使用 protobuf 实现,性能高,稳定性强。 https://github.com/Tencent/MMKV
官方对比:
IOS 循环写入随机的int 1w 次 |
Android 循环写入随机的int 1k 次 |
---|---|
运行过程
- 通过 mmap 系统调用,提供一段可供随时写入的内存块,App 只管往里面写数据,由操作系统负责将内存回写到文件,不必担心 crash 导致数据丢失
- 在内存中维护一份 k,v 字典数据
- 写入操作:将 value protobuf 序列化更新到字典,然后将字典再 protobuf 序列化追加到文件中(每个 Key 的更新都是直接追加到文件末尾,不是覆盖,只有当文件大小不足时才会进行 key 去重操作,所以文件大小会比通过常规方式(SharedPreferences)储存的 xml 文件大)
- 读取操作:将文件中的数据反序列化到内存的字典中,之后的每次 get 操作直接从内存中获取,获取到 value 之后再反序列化
原理
获取 MMKV 实例
|
|
对应的 Native 代码:
|
|
进一步调用 MMKV 类的静态方法:
|
|
题外话,MMKV 中的锁
MMKV 中封装了2个与锁相关的类:
- ThreadLock
- ScopedLock
|
|
|
|
TODO ⬇️
内存准备
通过 mmap 内存映射文件,提供一段可供随时写入的内存块,App 只管往里面写数据,由操作系统负责将内存回写到文件,不必担心 crash 导致数据丢失。
- 默认文件大小:系统内存分页大小,大小一般是 4096 byte, 4KB
- 文件存不够时,先对 key 去重,之后空间还是不够就增大文件,以内存分页大小的整数倍增加
|
|
数据组织
数据序列化方面选用 protobuf 协议
写入优化
考虑到主要使用场景是频繁地进行写入更新,将 kv 对象序列化后,append 到内存末尾。
比如写入一个字符串
|
|
空间增长
使用 append 实现增量更新
|
|
总结
- 适应于频繁写入读取的地方
- 文件大小会比常规方式大一些
- 内部的一些实现比较高效
- 函数传参采用右值引用,外部通过
move
调用将函数中局部变量的内容直接通过移动内存指向形参中,避免直接传参的内存拷贝
- 函数传参采用右值引用,外部通过