MMKV:轻巧高效的跨平台键值存储解决方案

MMKV:轻巧高效的跨平台键值存储解决方案

引言

在移动应用的开发中,数据存储是一个至关重要的环节。随着移动应用的普及和功能的增多,应用需要存储和管理各种类型的数据,包括用户配置信息、缓存数据、临时状态等。传统的数据存储方式如SharedPreferences在一些场景下存在性能瓶颈和局限性,因此我们需要寻找一种更轻量、高效的解决方案。

传统的数据存储方式,如SharedPreferences,虽然简单易用,但在某些情况下存在一些不足之处。首先,SharedPreferences存储的数据会被序列化成XML格式,导致存储和读取的速度相对较慢。其次,SharedPreferences是单线程操作的,如果在多个线程同时写入或读取数据,就容易出现数据安全和一致性问题。此外,SharedPreferences的内存占用也相对较高,特别是在存储大量数据时。

为了解决这些问题,我们需要寻找一种更轻量、高效的数据存储解决方案。而MMKV(Meituan Mapped Key-Value)就是一款非常优秀的跨平台键值存储库,由微信团队开发并开源。MMKV具有轻巧高效、跨平台支持的特点,是替代SharedPreferences的理想选择。

接下来,我们将介绍MMKV的优势,以及在移动应用开发中的实际应用场景。我们还会提供MMKV的使用指南,并进行性能测试,验证其高性能特点。最后,我们会总结MMKV的优势和适用场景,鼓励开发者尝试并采用MMKV,以提升应用的数据存储效率和性能表现。

MMKV简介

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

MMKV源起

在微信客户端的日常运营中,时不时就会因特殊文字引起系统 crash。为了解决这个问题,我们需要在关键代码前后进行计数器的加减,通过检查计数器的异常来发现引起闪退的异常文字。但是在一些包含大量 cell 的页面,如会话列表和会话界面,新增的计数器会影响滑动性能,并且这些计数器需要被永久保存以防止意外崩溃。为了满足这些需求,我们需要一个高性能的通用 key-value 存储组件。考虑到防崩溃方案的主要需求是实时写入,而 mmap 内存映射文件正好符合这一要求,我们决定尝试利用它来开发一个 key-value 组件,即 MMKV。

MMKV原理

  • 内存准备:通过 mmap 内存映射文件,为 App 提供一个可随时写入的内存块,App 只需将数据写入其中,而操作系统负责将内存内容写回文件,避免了因崩溃导致数据丢失的风险。
  • 数据组织:为了实现数据序列化,我们采用了 protobuf 协议,该协议在性能和空间利用方面表现优异。
  • 写入优化:考虑到写入更新频繁是主要使用场景,我们需要支持增量更新。因此,我们选择将增量 kv 对象序列化后,追加到内存末尾。
  • 空间管理:使用追加方式实现增量更新可能会导致文件大小无法控制地增长。为了在性能和空间利用之间取得平衡,我们需要做进一步的优化。

MMKV特点

  1. 轻巧高效:MMKV采用内存映射技术,将数据直接映射到内存中,避免了数据的序列化和反序列化过程,从而提高了读写速度。
  2. 跨平台支持:MMKV不仅支持在Android平台上使用,还提供了iOS、Windows等多个平台的支持,使开发者可以在不同平台上统一使用MMKV进行数据存储。
  3. 性能优越:相较于传统的SharedPreferences,MMKV具有更好的性能表现,尤其在大量数据读写和多线程操作时表现更为出色。

与SharedPreferences相比,MMKV在性能和功能上有明显优势。SharedPreferences的数据存储采用XML格式,而MMKV直接将数据映射到内存中,避免了XML解析过程,因此读写速度更快。此外,MMKV支持多线程读写操作,不会出现数据安全问题,而SharedPreferences在多线程操作时需要考虑同步和锁机制。

示例代码(对比使用SharedPreferences和MMKV进行数据存储的示例):

// 使用SharedPreferences存储数据
SharedPreferences sharedPreferences = context.getSharedPreferences("MyPrefs", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString("key", "value");
editor.apply();

// 使用MMKV存储数据
MMKV mmkv = MMKV.defaultMMKV();
mmkv.encode("key", "value");

// 从SharedPreferences读取数据
String valueFromPrefs = sharedPreferences.getString("key", "");

// 从MMKV读取数据
String valueFromMMKV = mmkv.decodeString("key");

通过以上示例代码的对比,可以清楚地看出MMKV相对于SharedPreferences的优势,包括更高的性能和更便捷的多线程支持。因此,MMKV是一款在移动应用开发中非常值得推荐和使用的数据存储库。

MMKV的优势

相较于SharedPreferences,MMKV具有以下优势:

  1. 性能更好:MMKV采用内存映射技术,将数据直接映射到内存中,避免了数据的序列化和反序列化过程,从而提高了读写速度。在大量数据读写和多线程操作时表现更为出色。
  2. 支持多线程读写:MMKV的底层使用了锁机制,支持多线程并发读写操作,不会出现数据安全问题。而SharedPreferences在多线程操作时需要考虑同步和锁机制。
  3. 内存占用更低:MMKV使用内存映射技术,不会像SharedPreferences那样将数据全部读入内存,因此内存占用更低,特别是在存储大量数据时表现更为明显。

MMKV实际应用场景

MMKV适用于移动应用开发中的各种场景,如替代SharedPreferences存储用户配置信息、缓存数据等。下面介绍一些常见的应用场景:

  1. 存储用户配置信息:移动应用通常需要保存用户的一些配置信息,如语言、主题、字体大小等。使用MMKV可以方便地将这些配置信息存储在本地,同时具有更高的读写速度和更低的内存占用。
  2. 缓存数据:移动应用中的一些常用数据,如网络请求数据、图片等,可以使用MMKV进行本地缓存。MMKV具有更高的读写速度和更低的内存占用,可以提升用户体验和应用性能。
  3. 状态保存:在某些场景下,应用需要保存一些临时状态,如用户登录状态、应用退出前的数据保存等。使用MMKV可以轻松地将这些状态存储在本地,并支持多线程并发读写操作,避免出现数据安全问题。

总之,MMKV在移动应用开发中具有广泛的应用场景,特别是在大量数据读写和多线程操作时表现更为出色。因此,我们鼓励开发者尝试并采用MMKV,以提升应用的数据存储效率和性能表现。

使用指南

5.1 Android平台上集成和使用MMKV

  1. 在项目的build.gradle文件中添加依赖:

    dependencies {
        implementation 'com.tencent:mmkv-static:1.2.7'
    }
    
  2. 在Application的onCreate方法中进行初始化:

    MMKV.initialize(this);
    
  3. 使用MMKV进行数据存储和读取:

    // 获取默认的MMKV对象
    MMKV mmkv = MMKV.defaultMMKV();
    
    // 存储数据
    mmkv.encode("key", "value");
    
    // 读取数据
    String value = mmkv.decodeString("key", "");
    

5.2 iOS平台上集成和使用MMKV

  1. 使用Cocoapods添加依赖:

    pod 'MMKV', '~> 1.2.7'
    
  2. 在AppDelegate.m文件中进行初始化:

    #import "MMKV.h"
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        [MMKV initialize];
        return YES;
    }
    
  3. 使用MMKV进行数据存储和读取:

    // 获取默认的MMKV对象
    MMKV *mmkv = [MMKV defaultMMKV];
    
    // 存储数据
    [mmkv setString:@"value" forKey:@"key"];
    
    // 读取数据
    NSString *value = [mmkv getStringForKey:@"key" defaultValue:@""];
    

5.3 示例代码

以下是一个简单的示例,展示如何在Android平台上使用MMKV进行数据存储和读取:

public class MainActivity extends AppCompatActivity {

    private MMKV mmkv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 获取默认的MMKV对象
        mmkv = MMKV.defaultMMKV();

        // 存储数据
        mmkv.encode("key", "value");

        // 读取数据
        String value = mmkv.decodeString("key", "");
        Toast.makeText(this, "读取到的数据:" + value, Toast.LENGTH_SHORT).show();
    }
}

以上代码中,我们在Activity的onCreate方法中初始化了MMKV,并使用encode方法存储了一条数据,然后使用decodeString方法读取该数据。

性能测试

为了验证MMKV的高性能特点,我们可以进行一些简单的性能测试,并与其他数据存储方式进行比较。在这里,我们将对SharedPreferences和MMKV进行读写性能的比较。

性能测试方案

  1. 读写大量数据:分别使用SharedPreferences和MMKV进行大量数据的写入和读取操作,记录时间并比较性能表现。
  2. 多线程读写测试:模拟多个线程同时进行读写操作,比较SharedPreferences和MMKV在多线程操作时的性能表现。
  3. 内存占用测试:比较SharedPreferences和MMKV在存储大量数据时的内存占用情况。

性能测试结果分析

通过性能测试,我们得到以下结论:

  1. 读写大量数据:在写入和读取大量数据时,MMKV的性能明显优于SharedPreferences,读写速度更快。
  2. 多线程读写测试:在多线程操作时,MMKV能够更好地保持数据的一致性,不会出现数据安全问题,而SharedPreferences需要考虑同步和锁机制。
  3. 内存占用测试:在存储大量数据时,MMKV的内存占用明显低于SharedPreferences,特别是在大规模数据存储时,MMKV的优势更加明显。

通过性能测试结果分析,可以得出结论:MMKV在性能方面具有明显的优势,包括读写速度更快、多线程操作更稳定、内存占用更低等特点。因此,开发者可以放心地选择MMKV作为数据存储方式,以提升应用的性能表现和用户体验。

结语

MMKV作为一种高性能的跨平台键值存储解决方案,具备许多优势和适用场景。通过对MMKV的特点和使用方法的介绍,我们可以得出以下结论:

  1. 高性能特点:MMKV具有卓越的读写性能,比传统的数据存储方式(如SharedPreferences)更快速有效。它采用了底层的mmap技术和序列化算法优化,以实现更高的读写速度和更低的内存占用。

  2. 适用场景:MMKV特别适用于移动应用开发中需要频繁进行大量数据读写的场景。例如,缓存管理、用户偏好设置、临时数据存储等。无论是小型应用还是大规模数据存储,MMKV都能够提供卓越的性能和稳定性。

因此,我们鼓励开发者积极尝试并采用MMKV作为数据存储解决方案,以提升应用的数据存储效率和性能表现。通过使用MMKV,开发者可以获得更好的用户体验,并提高应用在不同平台上的兼容性和可移植性。

总之,MMKV是一个强大且易于使用的数据存储库,它为移动应用开发者提供了一种高性能的替代方案。希望开发者们能够充分利用MMKV的优势,并将其应用于实际的项目中,以提升应用的数据存储效率和性能表现。

参考链接

https://github.com/Tencent/MMKV

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/383698.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu Desktop 删除文件

Ubuntu Desktop 删除文件 1. right mouse click on the file -> Move to Trash2. right mouse click on the file -> DeleteReferences 1. right mouse click on the file -> Move to Trash ​ 2. right mouse click on the file -> Delete ​​​ References …

Unity Meta Quest MR 开发(四):使用 Scene API 和 Depth API 实现深度识别和环境遮挡

文章目录 📕教程说明📕Scene API 实现遮挡📕Scene API 实现遮挡的缺点📕Depth API 实现遮挡⭐导入 Depth API⭐修改环境配置⭐添加 EnvironmentDepthOcclusion 预制体⭐给物体替换遮挡 Shader⭐取消现实手部的遮挡效果 此教程相关…

C++ //练习 5.6 改写上一题的程序,使用条件运算符(参见4.7节,第134页)代替if else语句。

C Primer(第5版) 练习 5.6 练习 5.6 改写上一题的程序,使用条件运算符(参见4.7节,第134页)代替if else语句。 环境:Linux Ubuntu(云服务器) 工具:vim 代码…

blender怎么保存窗口布局,怎么设置默认输出文件夹

进行窗口布局大家都会,按照自己喜好来就行了,设置输出文件夹如图 这些其实都简单。关键问题在于,自己调好了窗口布局,或者设置好了输出文件夹之后,怎么能让blender下次启动的时候呈现出自己设置好的窗口布局&#xff…

《CSS 简易速速上手小册》第10章:未来的 CSS(2024 最新版)

文章目录 10.1 CSS 的新特性和趋势10.1.1 基础知识10.1.2 重点案例:使用 CSS Grid 创建响应式图库10.1.3 拓展案例 1:利用 CSS 变量实现主题切换10.1.4 拓展案例 2:使用 lab() 颜色和 layer 规则优化样式 10.2 CSS Houdini:魔法般…

Day46 300最长递增子序列 674最长连续递增子序列 718最长重复子数组 1143最长公共子序列

300 最长递增子序列 给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。 子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序…

Kafka 入门笔记

课程地址 概述 定义 Kafka 是一个分布式的基于发布/订阅模式的消息队列(MQ) 发布/订阅:消息的发布者不会将消息直接发送给特定的订阅者,而是将发布的消息分为不同的类别,订阅者只接受感兴趣的消息 消息队列 消息队…

【北邮鲁鹏老师计算机视觉课程笔记】04 fitting 拟合

【北邮鲁鹏老师计算机视觉课程笔记】04 fitting 拟合 1 拟合的任务 如何从边缘找出真正的线? 存在问题 ①噪声 ②外点、离群点 ③缺失数据 2 最小二乘 存在的问题 3 全最小二乘 度量的是点到直线的距离而不是点在y方向到直线的距离 提示:点到直线的…

【北邮鲁鹏老师计算机视觉课程笔记】05 Hough 霍夫变换

【北邮鲁鹏老师计算机视觉课程笔记】05 Hough 霍夫变换 1 投票策略 考虑到外点率太高 ①让直线上的每一点投票 ②希望噪声点不要给具体的任何模型投票,即噪声点不会有一致性的答案 ③即使被遮挡了,也能把直线找出来 参数空间离散化 直线相当于就是m,b两…

vue核心技术(二)

◆ 指令补充 指令修饰符 通过 "." 指明一些指令 后缀,不同 后缀 封装了不同的处理操作 → 简化代码 v-bind 对于样式控制的增强 为了方便开发者进行样式控制, Vue 扩展了 v-bind 的语法,可以针对 class 类名 和 style 行内样式…

网络安全检查表

《网络攻击检查表》 1.应用安全漏洞 2.弱口令,默认口令 3.服务器互联网暴露 4.操作系统,中间件安全漏洞 5.研发服务器,邮件服务器等安全检查

PySpark(四)PySpark SQL、Catalyst优化器、Spark SQL的执行流程、Spark新特性

目录 PySpark SQL 基础 SparkSession对象 DataFrame入门 DataFrame构建 DataFrame代码风格 DSL SQL SparkSQL Shuffle 分区数目 DataFrame数据写出 Spark UDF Catalyst优化器 Spark SQL的执行流程 Spark新特性 自适应查询(SparkSQL) 动态合并 动态调整Join策略 …

Android---Jetpack Compose学习003

Compose 状态。本文将探索如何在使用 Jetpack Compose 时使用和考虑状态,为此,我们需要构建一个 TODO 应用,我们将构建一个有状态界面,其中会显示可修改的互动式 TODO 列表。 状态的定义。在科学技术中,指物质系统所处…

【XR806开发板试用】轻松连上华为云实现物联网

本文为极术社区XR806试用活动文章。 一.开始 偶然的机会在网上看到了鸿蒙开发板的试用,作为一个"老鸿蒙"岂能放弃这个机会,报名之后不出意料地得到了使用名额,在此感谢极术社区. 收到开发板之后其实还有点失望了,就那么一个小小的核心板,其他啥也没有,连一根数据线…

图灵日记--MapSet字符串常量池反射枚举Lambda表达式泛型

目录 搜索树概念实现性能分析和 java 类集的关系 搜索概念及场景模型 Map的使用Map常用方法 Set的说明常见方法说明 哈希表冲突-避免-负载因子调节冲突-解决-闭散列冲突-解决-开散列/哈希桶冲突严重时的解决办法 实现和 java 类集的关系 字符串常量池String对象创建intern方法 …

MongoDB 与 mongo-express docker 安装

MongoDB 和 mongo-express 与 MySQL 不同,MongoDB 为 NoSQL 数据库,MongoDB 中没有 table ,schema 概念,取而代之的 collection,其中 collection 存储的为 BSON 格式,是一种类似于 JSON 的用于存储 k-v 键…

每日五道java面试题之java基础篇(五)

第一题. final、finally、finalize 的区别? final ⽤于修饰变量、⽅法和类:final 修饰的类不可被继承;修饰的⽅法不可被重写;修饰的变量不可变。finally 作为异常处理的⼀部分,它只能在 try/catch 语句中,…

PyTorch深度学习实战(26)——多对象实例分割

PyTorch深度学习实战(26)——多对象实例分割 0. 前言1. 获取并准备数据2. 使用 Detectron2 训练实例分割模型3. 对新图像进行推断小结系列链接 0. 前言 我们已经学习了多种图像分割算法,在本节中,我们将学习如何使用 Detectron2 …

Netty Review - NioEventLoopGroup源码解析

文章目录 概述类继承关系源码分析小结 概述 EventLoopGroup bossGroup new NioEventLoopGroup(1); EventLoopGroup workerGroup new NioEventLoopGroup();这段代码是在使用Netty框架时常见的用法,用于创建两个不同的EventLoopGroup实例,一个用于处理连…

【计算几何】确定两条连续线段向左转还是向右转

确定两条连续线段向左转还是向右转 目录 一、说明二、算法2.1 两点的叉积2.2 两个段的叉积 三、旋转方向判别3.1 左转3.2 右转3.3 共线判别 一、说明 如果是作图,或者是判别小车轨迹。为了直观地了解,从当前点到下一个点过程中,什么是左转、…