KV存储SharedPreferences和MMKV的比较

一、SharedPreferences

优点:

1.键值对存储,轻量级存储

2.多种权限式存储,最终以xml方式存储

3.对于常规的轻量级而言比SQLite要好不少

4.xml处理时Dalvik实际解析处理,对于内存资源占用处理比较好

缺点:

1.不能跨进程,跨进程不安全

2.轻量级存储

3.加载慢,异步线程加载,并且没有线程优先级区分

4.全量写入,不管修改几条数据都会将所有数据重新刷一遍

5.卡顿,异步写入磁盘机制,未完成写入将一直等待

获取过程

​ getSharedPreferences主要通过获取ArrayMap<String(name),File> mSharedPrefsPaths 获取File,如果说file为空将通过getSharedPreferencesPath方法创建xml文件并返回file ,获取到file后根据File创建SharedPreferences。

​ SharedPreferences 创建过程:SharedPreferencesImpl是SharedPreferences具体实现类,首先会根据file从ArrayMap<File, SharedPreferencesImpl> cache缓存中寻找SharedPreferencesImpl,如果不存在将创建一个SharedPreferencesImpl并put到cache当中并返回SharedPreferencesImpl对象。其中获取缓存的方法是getSharedPreferencesCacheLocked,该方法是通过当前包名的方式获取cache对象。而SharedPreferencesImpl初始化时会调用方法将文件中读取内容,并将xml中存储的内容解析到map中。

​ SharedPreferencesImpl 在初始化时,会开启异步线程加载对应 name 的 XML 文件内容到 Map 容器中,如果文件内容较大,这一过程耗时还是不能忽视的,主要体现在如果此时我们操作 SharedPreferences 会导致线程等待问题,这里主要根据前面分析到的加载状态标志 mLoaded 变量有关,接下来我们就对其进行分析。

​ SharedPreferences 提供了 MODE_MULTI_PROCESS 这个 Flag 来支持跨进程,保证了在 API 11 以前的系统上,如果 sp 已经被读取进内存,再次获取这个 sp 的时候,如果有这个 flag,会重新读一遍文件。

使用过程
读取操作:

​ 在使用时,系统通过异步线程一次性将该文件内容加载到内存中,保存在 Map 容器中。实际后续我们对 SharedPreferences 的一些列 getXxx() 操作都是直接操作的该 Map 容器,内存中。在读取过程中会首先利用标志位判断SP文件是否加载,如果未加载完将会进入wait 状态。此时非常容易造成卡顿,如果再严重甚至会引发 ANR。

内容操作:

​ 1.每一次提交都会创建EditorImpl 的对象,EditorImpl 是Editor 具体实现类,操作数据都保存在 EditorImpl 中的 Map mModified 容器中,任务提交 commIt 或 apply 方法调用几乎一致,都会经过 commitToMemory 方法后调用 enqueueDiskWrite 方法。不同之处在于 enqueueDiskWrite 方法,如果当前是 commit 提交,则将数据写入文件任务在当前线程执行(同步),会返回是否提交成功; apply 提交则将写入文件任务在工作线程中完成 (异步),会提交到线程池中去执行。

​ 2.先执行commitToMemory 是提交缓存,再执行enqueueDiskWrite进行提交文件

​ 3.commitToMemory :mModified 保留着我们当前的改变,通过遍历该容器与 mMap(SharedPreferencesImpl 成员)容器做比较,比如相同 key 不同 value 此时将修改提交到 mMap 容器中,然后 mMap 中就保存了修正后,我们最后一次提交的数据。最后清空 mModified 容器。

在这里插入图片描述

二、MMKV

介绍:

​ 基于 mmap 内存映射的 key-value 组件,底层序列化/反序列化使用 protobuf 实现,性能高,稳定性强,支持多进程。

​ Mmap:mmap 是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对应关系。实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,即完成了对文件的操作而不必再调用 read,write等系统调用函数。相反,内核空间对这段区域的修改也直接反映用户空间,从而可以实现不同进程间的文件共享。由操作系统负责将内存回写到文件,不必担心 crash 导致数据丢失。
在这里插入图片描述

​ Protobuf:pb 在性能和空间占用上都有不错的表现。Protocol buffers 通常称为 Protobuf,是 Google 开发的一种协议,允许对结构化数据进行序列化和反序列化,不仅仅是一种消息格式,它还是一组用于定义和交换这些消息的规则和工具。 谷歌开发它的目的是提供一种比 XML更好的方式来进行系统间通信。该协议甚至超越了JSON,具有更好的性能,更好的可维护性和更小的尺寸。

​ 指针增长、内存重整、内存增长。将增量 kv 对象序列化后,直接 append 到内存末尾;这样同一个 key 会有新旧若干份数据,最新的数据在最后;那么只需在程序启动第一次打开 mmkv 时,不断用后读入的 value 替换之前的值,就可以保证数据是最新有效的。

​ 跨进进程实现:只需要将文件 mmap 到每个访问进程的内存空间,加上合适的进程锁,再处理好数据的同步,就能够实现多进程并发访问。

  • 文件锁,优点是天然 robust,缺点是不支持递归加锁,也不支持读写锁升级/降级,需要自行实现。
  • pthread_mutex,优点是 pthread 库支持递归加锁,也支持读写锁升级/降级,缺点是不 robust,需要自行清理。
特点:

1.支持多进程共享

2.效率更高,数据的读写操作快

3.使用了 AES CFB-128 算法来加密/解密,数据更安全

4.匿名内存

*mmap内存映射的实现过程:

(一)进程启动映射过程,并在虚拟地址空间中为映射创建虚拟映射区域

1、进程在用户空间调用库函数mmap,原型:void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);

2、在当前进程的虚拟地址空间中,寻找一段空闲的满足要求的连续的虚拟地址

3、为此虚拟区分配一个vm_area_struct结构,接着对这个结构的各个域进行了初始化

4、将新建的虚拟区结构(vm_area_struct)插入进程的虚拟地址区域链表或树中

(二)调用内核空间的系统调用函数mmap(不同于用户空间函数),实现文件物理地址和进程虚拟地址的一一映射关系

5、为映射分配了新的虚拟地址区域后,通过待映射的文件指针,在文件描述符表中找到对应的文件描述符,通过文件描述符,链接到内核“已打开文件集”中该文件的文件结构体(struct file),每个文件结构体维护着和这个已打开文件相关各项信息。

6、通过该文件的文件结构体,链接到file_operations模块,调用内核函数mmap,其原型为:int mmap(struct file *filp, struct vm_area_struct *vma),不同于用户空间库函数。

7、内核mmap函数通过虚拟文件系统inode模块定位到文件磁盘物理地址。

8、通过remap_pfn_range函数建立页表,即实现了文件地址和虚拟地址区域的映射关系。此时,这片虚拟地址并没有任何数据关联到主存中。

(三)进程发起对这片映射空间的访问,引发缺页异常,实现文件内容到物理内存(主存)的拷贝

注:前两个阶段仅在于创建虚拟区间并完成地址映射,但是并没有将任何文件数据的拷贝至主存。真正的文件读取是当进程发起读或写操作时。

9、进程的读或写操作访问虚拟地址空间这一段映射地址,通过查询页表,发现这一段地址并不在物理页面上。因为目前只建立了地址映射,真正的硬盘数据还没有拷贝到内存中,因此引发缺页异常。

10、缺页异常进行一系列判断,确定无非法操作后,内核发起请求调页过程。

11、调页过程先在交换缓存空间(swap cache)中寻找需要访问的内存页,如果没有则调用nopage函数把所缺的页从磁盘装入到主存中。

12、之后进程即可对这片主存进行读或者写的操作,如果写操作改变了其内容,一定时间后系统会自动回写脏页面到对应磁盘地址,也即完成了写入到文件的过程。

*mmap优点:

1、对文件的读取操作跨过了页缓存,减少了数据的拷贝次数,用内存读写取代I/O读写,提高了文件读取效率。

2、实现了用户空间和内核空间的高效交互方式。两空间的各自修改操作可以直接反映在映射的区域内,从而被对方空间及时捕捉。

3、提供进程间共享内存及相互通信的方式。不管是父子进程还是无亲缘关系的进程,都可以将自身用户空间映射到同一个文件或匿名映射到同一片区域。从而通过各自对映射区域的改动,达到进程间通信和进程间共享的目的。

*mmap与传统读写的区别:

传统的读写需要将磁盘数据拷贝到页缓存(内核空间)再拷贝到用户空间,而mmap则通过映射通过缺页异常将磁盘数据直接拷贝到用户进程空间

参考:
mmap原理之详解
Android 轻量级存储方案的前世今生
MMKV:用来替代SharePreference的高性能key-value组件

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值