一、MMKV 是什么?
- 腾讯开源的高性能通用 key-value 存储组件(GitHub: Tencent/MMKV)。
- 底层基于 mmap + protobuf,替代 SharedPreferences 解决性能和多进程一致性问题。
- 支持多平台(Android、iOS、Windows、macOS、Linux)。
二、核心原理
1. mmap(内存映射)
-
使用
mmap
将文件映射到内存,读写直接操作内存区域。 -
内存变更自动映射到文件,减少频繁磁盘 I/O。
-
优势:
- 避免整文件序列化/反序列化。
- 数据直接在内存读写,速度接近内存访问。
2. protobuf 序列化
- key/value 序列化存储在 mmap 区域。
- 新增/更新数据是追加写,不必全量覆盖旧数据。
- 定期触发一次“回收/重整”(类似 log compaction)释放空间。
3. 多进程一致性
- mmap 文件在多个进程间共享。
- 每个进程有文件锁/读写锁机制,保证数据一致性。
- 修改后可通过
mmkv.sync()
或mmkv.reloadFromFile()
及时更新内存。
三、MMKV vs SharedPreferences
特性 | SharedPreferences | MMKV |
---|---|---|
存储格式 | XML | Protobuf(二进制) |
写入方式 | 全量重写 XML | 追加写 |
底层 I/O | 文件流 | mmap |
多进程一致性 | 默认不支持 | 原生支持 |
性能 | 频繁写入慢 | 读写接近内存速度 |
类型支持 | 基本类型 + Set | 基本类型 + Set + 自定义字节数组 |
四、常见面试题
Q1:MMKV 为什么比 SharedPreferences 快?
- 读写都在内存(mmap)中完成,不需要频繁磁盘 I/O。
- protobuf 序列化高效,更新是增量写,不用全量重写文件。
- SP 每次写都重新生成整个 XML 文件,MMKV 只修改变化部分。
Q2:MMKV 会丢数据吗?
- 理论上可能:mmap 变更延迟刷盘,极端情况下(崩溃/断电)可能丢最后几毫秒的写入。
- 可调用
mmkv.sync()
主动刷盘降低风险。
Q3:MMKV 如何实现多进程读写一致性?
- 通过 mmap 映射同一个文件到不同进程,数据天然共享。
- 写操作加文件锁,防止并发冲突。
- 其他进程可
mmkv.reloadFromFile()
同步最新数据。
Q4:MMKV 有大小限制吗?
- 单个 mmap 文件默认最大 1MB,空间不足会自动扩容(翻倍策略)。
- 实际存储受设备文件系统限制(一般几百 MB 以上没问题)。
Q5:MMKV 支持事务吗?
- 不支持像数据库那样的事务机制,但单次写入是原子的(protobuf 完整性校验)。
- 多条数据更新可以批量操作后
sync()
。
Q6:MMKV 何时需要调用 sync()
?
- 默认依赖系统定时刷盘。
- 关键数据(支付状态、敏感标志)更新后建议立即
sync()
。
Q7:MMKV 跨进程实时性如何?
- 进程 A 写入后,进程 B 不会立即感知,需要主动调用
reloadFromFile()
或注册文件变更监听(自己实现)。
Q8:MMKV 替代 SP 时有哪些坑?
- 加密版本:初始化时要指定密钥,密钥丢失文件不可读。
- Set 线程安全:返回的是副本,和 SP 一样,不能直接改内部集合。
- 多进程同步:必须主动 reload。
- 数据迁移:第一次使用需从 SP 迁移数据(
MMKV.importFromSharedPreferences()
)。
五、常见追问
- Q:MMKV 为啥用 mmap,不直接读写文件?
直接读写文件每次都要系统调用 + 拷贝数据;mmap 让文件和内存共享同一块地址,减少数据复制。 - Q:MMKV 为什么用 protobuf 而不是 JSON/XML?
protobuf 二进制格式更紧凑,解析速度快,适合频繁读写。 - Q:MMKV 如何扩容?
检测到剩余空间不足 → 分配更大 mmap 文件 → 拷贝旧数据 → 指针切换到新映射。
六、总结面试答法
MMKV 是腾讯开源的高性能 key-value 存储,基于 mmap + protobuf 实现,读写几乎是内存速度,支持多进程数据一致性。相比 SharedPreferences 不用全量重写文件,支持更多数据类型。适合高频、小数据量的配置存储,重要数据可配合 sync(),多进程需 reloadFromFile 保证一致性。