Loading...

文章背景图

MMKV:微信高效轻量键值存储框架接入与使用指南

2026-10-16
0
- 字
- 分钟
|

MMKV 是微信团队开源的一款高效、轻量、易用的移动端键值存储框架,最初在微信 App 内部大规模使用,后来逐步开源并扩展到多个平台。它的核心思路非常直接:用 mmap(内存映射)让一段内存与磁盘文件保持同步,再用 protobuf 做值的编解码,从而在写入时几乎不需要等待磁盘 I/O,同时把序列化开销压到最低。

与 Android 系统自带的 SharedPreferences 相比,MMKV 不需要在每次写入后手动调用 apply 或 commit,数据即刻落盘;与 SQLite 相比,它没有建表、字段、SQL 解析的负担,特别适合保存用户偏好、开关状态、简单缓存这类结构化小数据。微信内部之所以自研并长期使用 MMKV,正是因为 SharedPreferences 在跨进程、频繁写入、容量增大等场景下会出现性能与一致性问题,而 SQLite 又过于沉重。MMKV 把两者的优点结合起来:既有键值存储的简单 API,又有接近数据库的可靠性与并发能力。

目前 MMKV 已支持 Android、iOS/macOS、Windows、POSIX 以及 HarmonyOS NEXT,并提供了实验性的 Kotlin Multiplatform(KMP)支持。它的设计目标是"小而美":代码只包含进程锁、编解码辅助和 mmap 逻辑,不引入多余依赖,包体增量控制在几十 K 到几百 K 之间。在微信内部,MMKV 承担了大量用户偏好、会话草稿、开关状态、AB 实验分组等数据的存储,经受住了亿级用户的考验。开源后,MMKV 被广泛应用于各类 Android、iOS、Windows、HarmonyOS 应用中,成为替代 SharedPreferences / NSUserDefaults 的事实标准之一,也是国内移动端本地存储领域被引用最多的开源项目之一。

使用 MMKV 的一个典型场景是替代 SharedPreferences:原来每次 putString 后还要 apply(),并且在主线程偶发 I/O 抖动;换成 MMKV 后,写入接口变成一次内存追加,调用方完全感知不到延迟。另一个场景是跨进程共享数据:Android 上多进程 App 往往需要在主进程和推送进程之间同步用户登录态,MMKV 的进程锁机制让这一切变得透明。在 HarmonyOS NEXT 与 Windows 桌面端,MMKV 也提供了一致的 C++ 接口,使得同一套存储逻辑可以跨平台复用。本文基于仓库 README 逐节完整翻译整理,覆盖各平台的特性、安装方式与快速上手示例。

一、项目官方信息

项目 信息
项目名称 MMKV
GitHub 仓库 Tencent/MMKV
出品方 腾讯 / 微信
最新版本 2.4.3(见 Releases)
开源协议 BSD 3-Clause(见 LICENSE.TXT)
支持平台 Android、iOS/macOS、Windows、POSIX、HarmonyOS NEXT、KMP
中文文档 README_CN.md
Wiki MMKV Wiki

二、官方图片与架构

MMKV 的底层数据结构是一个追加式的内存映射文件:每次写入都直接追加到 mmap 映射的内存末尾,操作系统会在合适的时机把脏页写回磁盘,因此调用方完全感知不到 I/O 延迟。这种设计的好处是写入操作只是在内存上做一次 memcpy,不需要经过用户态到内核态的系统调用,也不需要等待 fsync;坏处是文件会持续追加,需要靠 MMKV 内部的压缩与回收机制来控制大小。操作系统会在合适的时机把脏页写回磁盘,因此即使 App 崩溃,已写入的数据也基本不会丢失。

值使用 protobuf 编码,bool、int、string、bytes 等类型都有对应的编解码辅助函数。在多进程场景下,MMKV 内置进程锁,支持跨进程的并发读-读与读-写访问,这在 Android 多进程架构(例如推送服务、独立进程的 WebView)和桌面端多进程应用中尤为重要。

从工程角度看,MMKV 把键值存储的复杂度降到了最低:开发者不需要关心文件格式、不需要关心缓存失效、不需要关心序列化协议,只需要记住"写入即刻生效"。MMKV 内部会在文件过大时自动做一次压缩整理,把已被覆盖的旧值清理掉,避免文件无限膨胀。这种追加式日志结构(append-only log)的设计与 SQLite 的 WAL 模式有相似之处,但 MMKV 把它简化成了纯内存操作,没有任何后台线程。README 中给出了各平台的性能对比图:Android 上随机写入 int 类型 1000 次的基准图见 profile_android_mini.png,iOS 上随机写入 int 类型 10000 次的基准图见 profile_mini.png,更多基准数据见 Android benchmark 与 iOS benchmark。封面沿用本文既有官方仓库图,不再改动。

三、环境要求

根据 README 的说明,各平台的环境要求如下:

  • Android:从 v2.0.0 起不再支持 32 位架构,也不再支持 API level 21 与 22;如果需要 32 位或 API 21~22,应使用 v1.3.x LTS 系列。这是因为新版把代码重心放在了 64 位现代设备上,32 位维护成本过高。对于仍需兼容 Android 5.0 以下的老项目,官方明确建议停留在 v1.3.x 分支,不要强行升级。v2.0 以上版本在 API 上与 v1.x 保持兼容,迁移时主要是去掉 32 位 ABI 支持。
  • iOS/macOS:通过 CocoaPods 安装,需要先安装 CocoaPods;支持 iOS 与 macOS 双平台,Objective-C 与 Swift 工程均可直接使用。
  • Windows:从源码编译,需要 Visual Studio(官方使用 VS2017 开发,其他版本需调整 Platform Toolset);默认以 MT/MTd 运行时编译,若工程使用 MD/MDd 需统一运行时库设置,否则会链接报错。Windows 版本主要面向桌面端应用与编辑器插件场景,包体增量约 10K。
  • POSIX:通过 CMake 集成,需要支持 C++11 以上的编译器,适用于 Linux、macOS 等类 Unix 系统,也可在嵌入式 Linux 上交叉编译。POSIX 版本包体增量约 7K,非常轻量。
  • HarmonyOS NEXT:通过 OHPM 安装 @tencent/mmkv,需要 OpenHarmony 应用开发环境,目前为正式版本,API 与 Android/iOS 保持一致。
  • KMP:v2.4.3 为实验性版本,目前目标平台为 Android 与 iOS,支持 iosArm64、iosSimulatorArm64、iosX64,API 与产物布局未来可能调整,不建议生产环境直接使用。KMP 版本适合希望在 Compose Multiplatform 工程中共享存储逻辑的开发者做早期尝试。

四、部署步骤

1. Kotlin Multiplatform(实验性)

在共享模块的 commonMain 中加入依赖:

kotlin {
    sourceSets {
        commonMain.dependencies {
            implementation("com.tencent:mmkv-kmp:2.4.3")
        }
    }
}

初始化与打包细节见官方 KMP 指南。KMP 版本允许在 Android 与 iOS 之间共享同一份存储逻辑,适合 Compose Multiplatform 这类跨端工程。

2. Android 安装

在 app 模块的 build.gradle 中加入依赖:

dependencies {
    implementation 'com.tencent:mmkv:2.4.3'
    // replace "2.4.3" with any available version
}

其他安装方式见 Android Setup。Maven Central 上的坐标是 com.tencent:mmkv,版本号与 Release 对齐。加入依赖后无需额外权限声明,MMKV 只会在 App 沙箱目录内读写文件。

3. iOS/macOS 安装(CocoaPods)

  1. 安装 CocoaPods;
  2. 终端 cd 到工程目录,执行 pod repo update 让 CocoaPods 识别最新版本;
  3. 编辑 Podfile,在 app target 中加入 pod 'MMKV';
  4. 执行 pod install;
  5. 打开 CocoaPods 生成的 .xcworkspace 文件;
  6. 在源码中 #import <MMKV/MMKV.h> 即可。

其他安装方式见 iOS/macOS Setup。iOS 上也可以选择手动引入 framework 或源码编译,官方 Wiki 提供了详细步骤。

4. Windows 安装(源码)

git clone https://github.com/Tencent/MMKV.git

随后把 Core/core.vcxproj 加入解决方案,把 MMKV 工程加为依赖,在工程的 C/C++ → 常规 → 附加包含目录 加入 $(OutDir)include,在 链接器 → 常规 → 附加库目录 加入 $(OutDir),在 链接器 → 输入 → 附加依赖项 加入 mmkv.lib,最后在源码中 #include <MMKV/MMKV.h>。其他安装方式见 Windows Setup。需要特别注意运行时库一致性:MMKV 默认用 MT/MTd,若你的工程用 MD/MDd,必须把 MMKV 的运行时改成一致,反之亦然。如果使用的是不同于 VS2017 的 Visual Studio 版本,还需要在工程属性里把 Platform Toolset 切换到对应版本。

5. POSIX 安装(CMake)

克隆源码后,在 CMakeLists.txt 中加入:

add_subdirectory(mmkv/POSIX/src mmkv)
target_link_libraries(MyApp
    mmkv)

其他安装方式见 POSIX Setup。这种方式适合在 Linux 服务端或嵌入式设备上使用 MMKV 做本地缓存,与 Android/iOS 端共享同一份数据格式。

6. HarmonyOS NEXT 安装(OHPM)

ohpm install @tencent/mmkv

五、使用方法

1. Android 快速上手

在 Application.onCreate() 中初始化:

public void onCreate() {
    super.onCreate();

    String rootDir = MMKV.initialize(this);
    System.out.println("mmkv root: " + rootDir);
    //……
}

initialize 返回 MMKV 的根目录,开发者可以据此确认数据落在哪个沙箱路径。在多进程场景下,建议在每个进程的 Application.onCreate 中都调用一次 initialize,因为 mmap 是进程内的映射,不同进程需要各自建立映射才能共享同一份文件。initialize 返回 MMKV 的根目录,开发者可以据此确认数据落在哪个沙箱路径。MMKV 提供全局实例,可直接使用:

import com.tencent.mmkv.MMKV;

MMKV kv = MMKV.defaultMMKV();

kv.encode("bool", true);
boolean bValue = kv.decodeBool("bool");

kv.encode("int", Integer.MIN_VALUE);
int iValue = kv.decodeInt("int");

kv.encode("string", "Hello from mmkv");
String str = kv.decodeString("string");

写入 bool、int、string 都只要一行 encode,读取用对应的 decodeXxx。所有修改即刻生效,不需要 apply。MMKV 还支持多进程访问,完整教程见 Android Tutorial。对于更复杂的数据结构,MMKV 还支持传入自定义的 MMKV 实例名,把不同业务的数据隔离到不同文件中,避免单文件过大。例如可以为用户偏好创建一个 defaultMMKV,为聊天草稿创建一个名为 draft 的实例,两者互不影响。

2. iOS/macOS 快速上手

在 -[MyApp application:didFinishLaunchingWithOptions:] 中初始化:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // init MMKV in the main thread
    [MMKV initializeMMKV:nil];

    //...
    return YES;
}

直接使用全局实例:在主线程初始化后,MMKV 即可在任意线程读写,无需加锁。

MMKV *mmkv = [MMKV defaultMMKV];

[mmkv setBool:YES forKey:@"bool"];
BOOL bValue = [mmkv getBoolForKey:@"bool"];

[mmkv setInt32:-1024 forKey:@"int32"];
int32_t iValue = [mmkv getInt32ForKey:@"int32"];

[mmkv setString:@"hello, mmkv" forKey:@"string"];
NSString *str = [mmkv getStringForKey:@"string"];

多进程访问教程见 iOS Tutorial。iOS 上 MMKV 的包体增量不到 30K/架构,对 IPA 体积影响极小,且不需要任何额外配置即可使用。

3. Windows / POSIX 快速上手

在 main() 中初始化:Windows 与 POSIX 共用同一套 C++ API,区别仅在于初始化时传入的根目录路径。

#include "MMKV.h"

int main() {
    std::string rootDir = getYourAppDocumentDir();
    MMKV::initializeMMKV(rootDir);
    //...
}

读写示例:

auto mmkv = MMKV::defaultMMKV();

mmkv->set(true, "bool");
std::cout << "bool = " << mmkv->getBool("bool") << std::endl;

mmkv->set(1024, "int32");
std::cout << "int32 = " << mmkv->getInt32("int32") << std::endl;

mmkv->set("Hello, MMKV for Windows", "string");
std::string result;
mmkv->getString("string", result);
std::cout << "string = " << result << std::endl;

Windows 教程见 Windows Tutorial,POSIX 教程见 POSIX Tutorial。C++ API 与 Android/iOS 风格一致,区别在于初始化需要传入应用文档目录,读取 string 时用引用参数接收结果。

4. HarmonyOS NEXT 快速上手

在 EntryAbility.onCreate() 中初始化:HarmonyOS 版本需要在 Ability 启动时传入应用上下文,才能确定 MMKV 的根目录。

import { MMKV } from '@tencent/mmkv';

export default class EntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    let appCtx = this.context.getApplicationContext();
    let mmkvRootDir = MMKV.initialize(appCtx);
    console.info('mmkv rootDir: ', mmkvRootDir);
    ……
  }

读写示例:

import { MMKV } from '@tencent/mmkv';

let mmkv = MMKV.defaultMMKV();
mmkv.encodeBool('bool', true);
console.info('bool = ', mmkv.decodeBool('bool'));

mmkv.encodeInt32('int32', Math.pow(2, 31) - 1);
console.info('max int32 = ', mmkv.decodeInt32('int32'));

mmkv.encodeInt64('int', BigInt(2**63) - BigInt(1));
console.info('max int64 = ', mmkv.decodeInt64('int'));

let str: string = 'Hello OpenHarmony from MMKV';
mmkv.encodeString('string', str);
console.info('string = ', mmkv.decodeString('string'));

let arrayBuffer: ArrayBuffer = StringToArrayBuffer('Hello OpenHarmony from MMKV with bytes');
mmkv.encodeBytes('bytes', arrayBuffer);
let bytes = mmkv.decodeBytes('bytes');
console.info('bytes = ', ArrayBufferToString(bytes));

完整文档见 HarmonyOS NEXT Tutorial。HarmonyOS 版本支持 bool、int32、int64、string、bytes 等类型,与其他平台保持一致的 API 风格,包体增量约 600K/架构(HAR/HAP 打包后更小)。

六、核心特性

各平台的特性描述基本一致:高效——使用 mmap 保持内存与文件同步,使用 protobuf 编解码,充分利用各平台原生能力达到最佳性能;易用——随用随取,所有修改即刻保存,无需调用 sync、apply、commit 或 synchronize;轻量——只包含进程锁、编解码辅助和 mmap 逻辑,代码非常整洁,包体增量在 Android 上约 50K/架构(打包后更小),iOS/macOS 上不到 30K/架构,Windows 上约 10K,POSIX 上约 7K,HarmonyOS NEXT 上约 600K/架构(打包后更小)。

此外 Android、Windows、POSIX、HarmonyOS 均支持跨进程并发读-读与读-写访问,这对多进程应用至关重要。相比 SharedPreferences 只能在单进程内可靠工作,MMKV 的多进程能力让它能直接服务于推送进程、WebView 进程等场景。相比 Realm 或 SQLite,MMKV 没有 schema 迁移、没有查询语言、没有后台线程,学习成本几乎为零。在包体方面,MMKV 的设计哲学是"能少则少":除了核心 mmap 与 protobuf 逻辑外,不引入任何第三方依赖,因此在 Android 上每架构只增加约 50K,在 iOS 上每架构不到 30K,在 Windows 上约 10K,在 POSIX 上约 7K,在 HarmonyOS 上约 600K,打包压缩后体积更小。这种轻量性让 MMKV 几乎不会对 App 包体造成负担。

七、常见问题(FAQ)

  • 如何开始使用? 按上文在 App 启动时初始化,然后直接使用 defaultMMKV() 读写即可,无需任何额外配置。
  • 多进程怎么用? 参考各平台 Tutorial 中的多进程章节,MMKV 已内置进程锁,跨进程并发安全。
  • 历史版本兼容? 需要 32 位或 API 21~22 的 Android 项目请使用 v1.3.x LTS,新版 v2.0 以上只支持 64 位。
  • 数据怎么备份? MMKV 文件就放在沙箱根目录下,直接复制整个目录即可备份;卸载重装后把文件放回原位即可恢复。
  • 支持哪些数据类型? bool、int、long、float、double、string、byte[] 都有对应的 encode/decode 接口,复杂对象可序列化为 bytes 后存储。
  • 文件会无限增大吗? 不会,MMKV 内部会在文件过大时自动压缩整理,把已被覆盖的旧值清理掉。
  • 可以加密吗? 官方提供了基于 MMKV 的加密扩展,详见 Wiki 中的加密章节,可对敏感数据做透明加密。
  • 遇到问题? 先查 FAQ,仍无法解决可提交 Issue。
  • 隐私政策? MMKV 不采集、不上传任何个人信息,详见 MMKV SDK 个人信息保护规则。MMKV 采用 Contributor Covenant 行为准则,欢迎遵守公约的开发者参与贡献,共同维护这个项目,让它在更多平台上发光发热。
  • 如何贡献? 见 CONTRIBUTING.md,也可加入 Tencent OpenSource Plan。MMKV 已正式加入腾讯面向设备的服务产品联盟,与其他联盟成员共建开放互利的前端技术产品生态。

八、跳转链接

评论交流

文章目录