MMKV 几见
引言
最近微信开源了 mmkv,之前曾经深为 android 跨进程数据共享和通信所困惑,用 contextprovider 里面 sharedpreference,也曾经考虑过用文件读写来实现,可是 Java 端对文件读写跨进程操作实在是没有很大可操作余地,ndk写的话又太耗时而且无法保障测试性能等等问题。现在开源的 mmkv 正好弥补来这一块空缺,而且结果微信检验,在性能和安全方面感觉还是比较靠谱的。
详解
跨进程数据共享主要有以下问题:
- 多进程数据如何保持数据一致性即写更新,读的都是最新的
- 如何保证稳定性和高效性,降低性能消耗
mmkv 最初的设计并不是为了考虑多进程情况。主要是提高了 key-value 存储的性能。
- 使用 protobuf 二进制来存储数据。作为高效数据压缩编码方式,无疑提高了写入和读取性能
- 增量更新。通过将修改数据写在后面,等待内存满了之后触发重整进行整理。提高了修改操作的性能,不需要再去查询旧数据进行修改。当然在不断触发内存重整的情况下会大大损耗性能(回到),但一般情况下这明显是低概率事件.且存储限制会指数增长。
- mmap 文件映射内存,省去一次拷贝的时机。
而之后考虑 android 多进程的情况,针对多进程需要考虑情况:
- 指示器。拿文件前面几个字节作为当前写的位置。多进程模式下,每个进程读写时候都要检查一下当前和内存是否一致。不一致则需要读取新写的。
- 锁。使用了文件读写锁,在外部做了封装,可以更好支持。
- 增加了 Ashmem 的支持。
使用
- 使用简单,最好直接使用 static 的依赖,因为普通的依赖会添加 libc++_shared.so ,会导致包比 static 大2倍以上
1
implementation 'com.tencent:mmkv-static:1.0.19'
- 性能测试,多进程和单进程性能相差很小。1000 次写稳定在几十毫秒,在新机器上会达到20、30毫秒内。1000 次读能稳定在10毫秒左右。偶尔可能会有波动。总体看性能比读写 file 高10倍以上,比 sharedference 写高百倍(因为 sharedference 就算使用 apply,在最后未完成也要补回来),读因为 sharedference 是内存操作所以相差不大。
- 因为 mmkv 在 native 层做了较多缓存,所以在使用是可以不需要考虑创建性能单例等等问题
注意事项
使用 file 没有特别注意的地方,但是要注意自己不要每次都添加很大的数据,很频繁触发内存重整,效率会很低。
使用 Ashmem 的话,有很多注意地方。可以的话能不用就不用,使用 file + 逻辑来代替
- 内部实现实际使用了 MMKVContentProvider 来传递文件描述符
- 在 X86 某些机型上很容易 anr
- 如果 MMKVContentProvider 所在进程挂了重新启动,会导致 ashmem 生成新的,和其它还存在进程不一致。
因为 mmkv 无法保障原子性操作。类似乐观锁的需要自己实现
mmkv 采用 mmap,实际上 binder 内部实现也是使用 mmap。所以不需要过多担心内部稳定性