微信MMKV原理与实现(二):文件数据结构

说到轻量级的数据持久化,大家最先想到的就是SharedPreferences(以下简称SP)了,SP存储方式为xml,直接使用I/O流进行文件的读写,这就形成了一个弊端:每次写入或修改都需要替换掉原来的数据,并将所有数据 重新写入文件。可想而知,如果一个sp文件的内容过多,那么再写入的时候会造成卡顿,甚至会有 ANR的风险。

一、I/O

1、先看一下SP的工作原理

在这里插入图片描述

虚拟内存被操作系统划分成两块:用户空间和内核空间,用户空间是用户程序代码运行的地方,内核空间是内核代码运行的地方。为了安全,它们是隔离的,即使用户的程序崩溃了,内核也不受影响。

2、使用I/O写入文件的流程

1、调用write,告诉内核需要写入数据的开始地址与长度

2、内核将数据拷贝到内核缓存

3、由操作系统调用,将数据拷贝到磁盘,完成写入

可见,将数据写入文件需要将数据拷贝两次,再写入到文件中,如果数据量过大,也会有很大的性能损耗。

二、MMKV

1、什么是MMKV

为了解决上述问题,微信团队基于MMAP研发了MMKV来代替SP。

MMKV 是基于 mmap 内存映射的 key-value 组件,底层序列化/反序列化使用 protobuf 实现,性能高,稳定性强。从 2015 年中至今在微信上使用,其性能和稳定性经过了时间的验证。近期也已移植到 Android / macOS / Windows 平台,一并开源。

2、MMAP(memory mapping)

Linux通过将一个虚拟内存区域与一个磁盘上的对象关联起来,以初始化这个虚拟内存区域的内容,这个过程称为内存映射(memory mapping)。

在这里插入图片描述

对文件进行映射,会在进程的虚拟内存分配地址空间,创建映射关系。实现这样的映射关系后,就可以采用指针的方式读写操作这一段内存,而系统会自动回写到对应的文件磁盘上。

3、MMAP优势

  • MMAP对文件的读写操作只需要从磁盘到用户主存的一次数据拷贝过程,减少了数据的拷贝次数,提高了文件读写效率。
  • MMAP使用逻辑内存对磁盘文件进行映射,操作内存就相当于操作文件,不需要开启线程,操作MMAP的速度和操作内存的速度一样快;
  • MMAP提供一段可供随时写入的内存块,App 只管往里面写数据,由操作系统如内存不足、进程退出等时候负责将内存回写到文件,不必担心 crash 导致数据丢失。

下面来对比一下SP可MMKV同事存储1000条数据的耗时:

在这里插入图片描述
在这里插入图片描述

由此可见,MMKV的写入速度远超过了SP!这也是MMAP的优势所在。(读取的时候两者都是在app初始化时将数据保存在了一个map中,从内存中读取,所以两者的读取速度是没什么分别的。)

三、Protobuf协议

1、 什么是protobuf协议

protobuf 是google开源的一个序列化框架,类似xml,json,最大的特点是基于二进制,比传统的XML表示同样一段内容要短小得多。

MMKV正式基于protobuf协议进行数据存储,存储方式为增量更新,也就是不需要每次修改数据都要重新将所有数据写入文件了。

2、数据结构

在这里插入图片描述

protobuf是二进制存储格式,第一位代表的是key和value的总长度,后面是key长度->key, value长度->value。。。。。 依次排列,可以用二进制查看工具来看一下:

在这里插入图片描述

3、写入方式

为了方便理解,这里拿整型编码举例:

1个字节保存7位数据,第1位为标志位

如果写入的数据 <= 0x7f 那么使用7位即1个字节表示,完成编码

如果写入的数据 > 0x7f 那么先记录低7位数据,并将最高位设为1,继续执行判断

16进制 0x7f
10进制 127
2进制 0111 1111
在这里插入图片描述

以上代码就是整型的写入方式。

4、举例

为了更好的说明编码和解码的原理,我们拿一个整型来进行计算: 318242

编码

首先将318242进行二进制转换

  1. 编码318242 -》

0100 1101 1011 0010 0010 (步1)

  1. 大于0x7f,取最低7位,最高位补1:

1010 0010 ------------》写出到文件

  1. 将步1的数据右移7位

0000 0000 1001 1011 0110 (步2)

  1. 再取低7位,最高位补1

1011 0110 ------------》写出到文件

  1. 再将步2的数据右移7位

0000 0000 0000 0001 0011(步3)

  1. 再取低7位,最高位补1

1001 0011 ------------》写出到文件

  1. 再将步3的数据右移7位

0000 0000 0000 0000 0000 (步4)

  1. 再取低7位,因为这7位小于0x7f,不需要补1,直接写出

0000 0000 ------------》写出到文件

经过以上8个步骤,protobuf就为318242编码完成了。

解码

拿到上面写入的几组数据:

  1. 1010 0010
  2. 1011 0110
  3. 1001 0011
  4. 0000 0000

然后从后面往前拼接:(注意一下,因为前3个数据只有后7位是有效数据,拼接时要去掉首位)

1)将4拼接到3前面:

0000 0000 001 0011

2)再将上面的数据拼接到2前面:

0000 0000 001 0011 011 0110

3)再拼接到1前面:

0000 0000 001 0011 011 0110 010 0010

去除无效位:

0 001 0011 011 0110 010 0010

这样就得到了原二进制码(0100 1101 1011 0010 0010)。

四、缺点

任何事情都是有两面性的,MMKV也有它的缺点。

在这里插入图片描述

上面简单的模拟了一下MMKV存储数据的流程。由上可知,Linux采用了分页来管理内存,存入数据先要创建一个文件,并要给这个文件分配一个固定的大小。如果存入了一个很小的数据,那么这个文件其余的内存就会被浪费。相反如果存入的数据比文件大,就需要动态扩容。

不过具体情况要具体分析,大多数情况是优大于弊的!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容