APP优化 —— MMAP内存映射
mmap
一种内存映射文件的方法
mmap将一个文件或者其它对象映射进内存。文件被映射到多个页上,如果文件的大小不是所有页的大小之和,最后一个页不被使用的空间将会清零。mmap在用户空间映射调用系统中作用很大。
头文件 <sys/mman.h>
函数原型
void* mmap(void* start,[size_t](https://baike.baidu.com/item/size_t/8101179?fromModule=lemma_inlink) length,int prot,int flags,int fd,off_t offset);
int [munmap](https://baike.baidu.com/item/munmap/4568227?fromModule=lemma_inlink)(void* start,size_t length);
映射条件
mmap()必须以PAGE_SIZE为单位进行映射,而内存也只能以页为单位进行映射,若要映射非PAGE_SIZE整数倍的地址范围,要先进行内存对齐,强行以PAGE_SIZE的倍数大小进行映射。
mmap基础概念
mmap是一种内存映射的方法,这一功能可以用在文件的处理上,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。在编程时可以使某个磁盘文件的内容看起来像是内存中的一个数组。如果文件由记录组成,而这些记录又能够用结构体来描述的话,可以通过访问结构数组来更新文件的内容。
内存映射原理
mmap是一种内存映射文件的方法,它将一个文件映射到进程的地址空间中,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。
当磁盘地址和进程虚拟地址建立关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写数据到磁盘上,即直接完成了对文件的操作而不必在调用read/write等系统调用函数。同样的如果磁盘中内容有修改,也会直接反映到用户空间其数据改变了。
所以通过mmap映射方式可以使不同进程间共享磁盘文件,其共享对象可为普通文件或匿名文件
映射内存的分配
mmap映射区域大小必须是物理页大小(page_size)的整倍数(在Linux中内存页通常是4k)。因为内存的最小粒度是页,而进程虚拟地址空间和内存的映射也是以页为单位。为了匹配内存的操作,mmap从磁盘到虚拟地址空间的映射也必须是页。
例如,有一个文件的大小是5K,mmap函数从文件的起始位置映射5K到虚拟内存中,由于内存物理页是4K,虽然映射的文件只有5K,但是实际上映射到内存区域的内存是8K,以便满足物理页大小的整数倍。映射后对5~8K的内存区域用零填充,对这部分的操作不会报错也不会写入到原文件中。
传统I/O读写流程
- 用户进程发起文件数据的读请求
- 内核通过查找进程文件符表,定位内核已打开文件集上的文件信息,从而找到文件inode
- inode在address_space上查找要请求的文件页是否已缓存在页缓存中
- 如已在缓存页中,则直接返回这片文件页上的内容
- 如不在缓存页上,就会引发缺页中断。 当发生缺页中断时,内核则调用nopage函数把所缺的页从磁盘装入到内存内核中及Page Cache中。接着再发起读页面过程,从而将数据从页缓存中拷贝到用户空间中

特点:
常规文件操作为了读写效率和保护磁盘,使用了页缓存机制 页缓存处在内核空间中,不能直接被用户进程直接寻址,需要将数据从页缓存中拷贝到主内存
mmap读写流程
- 用户进程调用进程内存映射函数库mmap,当前进程在线程虚拟地址空间中寻找一段空闲的满足要求的虚拟地址。
- 在当前进程的虚拟地址空间中,寻找一段满足要求的虚拟地址
- 为此虚拟地址分配一个虚拟内存区域,vm_area_struct结构
- 初始化该虚拟内存区域
- 插入该虚拟内存区域到进程的虚拟地址区域链表中
- 内核同样收到请求后会调用内核的mmap函数,实现地址映射关系配对,即进程虚拟地址空间<< >>文件磁盘地址 关系映射,该映射与内核内存没有任何关联
- 进程调用mmap函数,内核同样会得到消息,最终内核调用自身的系统调用函数mmap。(两mmap函数不一样)
- 内核mmap函数通过虚拟文件系统定位到文件磁盘物理地址。
- 通过remap_pfn_range()建立页表,实现了文件地址和虚拟地址区域的映射关系。
- 进程的读/写操作访问虚拟地址空间这一段地址,如果读写操作该改变了虚拟地址空间内容,则一段时间后系统会自动回写脏页面到对应的磁盘地址中,即完成了写入文件的操作。
- 修改的脏页面不会立即更新,而是有延时,可以通过msync()来强制同步。通过此法能将所写的内容立即保存到磁盘中

特点:
- 用户空间与内核空间磁盘块通过映射直接交互,不在间接通过页缓存。
- 文件读写操作跨过了页缓存,数据拷贝次数减少为只需一次
- 借助硬盘的大空间,对于大规模数据的读写避免对页内存空间大小的依赖,提高操作效率。
mmap数据读写的性能提升就在于对数据的读写拷贝次数,mmap只需要一次系统调用(一次拷贝),后续操作不需要系统调用。并且访问的数据不需要在page cache和用户缓冲区之间拷贝。
mmap读写优势
- 对文件的读取操作跨过了页缓存,减少了数据的拷贝次数,用内存读写取代I/O读写,提高了文件读取效率。
- 实现了用户空间和内核空间的高效交互方式。两空间的各自修改操作可以直接反映在映射的区域内,从而被对方空间及时捕捉。
- 提供进程间共享内存及相互通信的方式。不管是父子进程还是无亲缘关系的进程,都可以将自身用户空间映射到同一个文件或匿名映射到同一片区域。从而通过各自对映射区域的改动,达到进程间通信和进程间共享的目的。
如果进程A和进程B都映射了区域C,当A第一次读取C时通过缺页从磁盘复制文件页到内存中;但当B再读C的相同页面时,虽然也会产生缺页异常,但是不再需要从磁盘中复制文件过来,而可直接使用已经保存在内存中的文件数据。
可用于实现高效的大规模数据传输。内存空间不足,是制约大数据操作的一个方面,解决方案往往是借助硬盘空间协助操作,补充内存的不足。但是进一步会造成大量的文件I/O操作,极大影响效率。但凡是需要用磁盘空间代替内存的时候,mmap都可以发挥其功效。
mmap的使用
mmap的函数位于内核的<sys/mman.h> 头文件中,与其相关的几个函数也列出如下:
// 用户进程调用, 函数用于将文件映射到内存
void* mmap(void addr, size_t length, int prot, int flags, int fd, off_t offset);
// 函数用于取消映射,进程在映射空间对共享内容的改变并不直接写回到磁盘文件中,往往在调用munmap() 后才执行该操作。
int munmap(void *addr, size_t length);
// 函数用于实现磁盘文件内容与共享内存区中的内容一致,即同步操作。
// 除了调用munmap取消映射,我们也可以调用msync()实现磁盘上文件内容与内核内存的内容一致
int msync(void * addr, size_t len, int flags);
mmap的使用场景
1.Linux进程的创建
Linux执行一个程序,这个程序在磁盘上,为了执行这个程序,需要把程序加载到内存中,这时也是采用的是mmap。你可以从/proc/pid/maps看到每个进程的mmap状态。
- 内存分配
我们使用c库的malloc申请内存,malloc的分配内存有两个系统调用,一个brk,另一个就是mmap。
mmap不仅可以映射文件,也可以映射内存,当mmap使用的flag是MAP_ANONYMOUS,称为建立匿名映射,此时会忽略参数fd,不涉及文件,而且映射区域无法和其他进程共享。匿名映射存储的数据就是在物理内存上,不属于任何文件。malloc分配内存底层就是用mmap的匿名映射来操作的。
- Binder进程间通信
了解进程间通信的人都知道Android使用的是Binder进行进程间通信,它的效率高于Linux其他传统的进程间通信,因为它只要一次拷贝,而之所以只需要进行一次拷贝的原因就在于使用了mmap。
最后,以上就是app深度优化需要学习的MMAP内存映射的原理解析以及使用方法;跟多Android核心技术或是Android性能优化的学习;可以点击《Android核心优化性能学习手册》。点击查看类目

mmap优缺点
优点
- mmap 防止数据丢失,提高读写效率
- 精简数据,以最少量的数据局量表示最多的信息,减少数据大小
- 增量新增,避免每次数据新增时的全量写入
- mmap对文件的读写操作只需要对磁盘到用户主存的一次数据拷贝过程,减少了数据的拷贝次数,提高文件读写效率。
- mmap使用逻辑内存对磁盘文件进行映射,操作内存就相当于操作文件,不需要开启线程,操作mmap的速度和操作内存的速度一样快。
- mmap提供一块随时写入的内存,app只管往里写入数据,由操作系统如内存不足。进程退出时负责将内存写回到文件。不必担心crash导致数据丢失。
- mmap的适用场景是大文件的频繁读写,这样就可以节省很多IO的耗时。
- 即使进程意外死亡, 也能够通过 Linux 内核的保护机制, 将进行了文件映射的内存数据刷入到文件中, 提升了数据写入的可靠性
缺点:
- 因为mmap是按照页存储方式进行存储,每页4096字节,如果数据只有100字节,则正页将有大大的浪费。
- 写回文件的工作由系统负责,但是并不是实时的,是定期写回到磁盘的,中间如果发生内核崩溃、断电等,还是会丢失数据,不过可以通过msync将数据同步回磁盘。
相关文章:
APP优化 —— MMAP内存映射
mmap 一种内存映射文件的方法 mmap将一个文件或者其它对象映射进内存。文件被映射到多个页上,如果文件的大小不是所有页的大小之和,最后一个页不被使用的空间将会清零。mmap在用户空间映射调用系统中作用很大。 头文件 <sys/mman.h> 函数原型 v…...
paddle.vision 与 torchvision 中的box NMS使用方式
torchvision 中有多个用于计算 BBox NMS 的 API, 在本篇氵文中, 使用 torchvision.ops.boxes.batched_nmspaddle.vision 中通过 paddle.vision.ops.nms 来进行多个 Box 的 NMS 操作 1. torchvision 中 batched_nms 操作 torchvision batched_nms def batched_nms(boxes: to…...
php mysql校园帮忙领取快递平台
1、后台管理员用户名hsg 密码hsg 2、开发语言:PHP,数据库为MySql 3、数据库连接字符串在conn.php中修改 4、运行环境wamp5.1.7或者appserv2.5.9 5.程序编码gbk.不支持php5.3以上版本 6.本人发布的程序一律享有免费运行一次…...
C/C++开发,无可避免的内存管理(篇二)-约束好跳脱的内存
一、养成内存管理好习惯 1.1 养成动态对象创建、调用及释放好习惯 开发者手动接管内存分配时,必须处理这两个任务。分配原始内存时,必须在该内存中构造对象;在释放该内存之前,必须保证适当地撤销这些对象。如果你的项目是c项目&am…...
【Java】让我们对多态有深入的了解(九)
目录 (1)接口的基本介绍编辑 (2)接口的注意事项和细节 1.接口不能被实例化 2.接口中所有方法是public方法,接口中的抽象方法,可以不用abstract修饰 3.一个普通类实现接口,必须将接口所有…...
12 个适合做外包项目的开源后台管理系统
1.D2admin 开源地址:https://github.com/d2-projects/d2-admin 文档地址:https://d2.pub/zh/doc/d2-admin/ 效果预览:https://d2.pub/d2-admin/preview/#/index 开源协议:MIT 2.vue-element-admin 开源地址:https…...
鼠标更换指针图案和更改typora的主题
鼠标更换指针图案 由此偶然看见好几个朋友都使用了新的图案替换掉了原有的鼠标图案,今天寻思自己也换一个图案 主要是觉得鼠标大一点儿会好看一些,所以就找了一些教程 官方教程,小的变动 当然最多的是官方教程,如果你只是想要…...
【洛谷 P1563】[NOIP2016 提高组] 玩具谜题(模拟+结构体数组+指针)
[NOIP2016 提高组] 玩具谜题 题目背景 NOIP2016 提高组 D1T1 题目描述 小南有一套可爱的玩具小人, 它们各有不同的职业。 有一天, 这些玩具小人把小南的眼镜藏了起来。 小南发现玩具小人们围成了一个圈,它们有的面朝圈内,有的面朝圈外。如下图: 这时 singer 告诉小南一个谜…...
阿里测试经验7年,从功能测试到自动化测试,我整理的超全学习指南
做测试七年多,有不少人问过我下面问题: 现在的手工测试真的不行了吗? 测试工程师,三年多快四年的经验,入门自动化测试需要多久? 自学自动化测试到底需要学哪些东西? 不得不说,随着…...
Educational Codeforces Round 143 (Rated for Div. 2)
Educational Codeforces Round 143 (Rated for Div. 2) D. Triangle Coloring 思路: 每个环都需要取最大值,那么我们讨论一个环获得最大值选的两条边的可能取法: 显然:如果三边相等,这个环有3种取法。如…...
业务代码编写过程中如何「优雅的」配置隔离
思考 不同的处理方式 1.常规的处理方式,通过某种规则判断区分代码环境 // 获取环境标识 const env getCurrentEnv();if (env dev) {// do something } else if (env test) {// do something } else if (env prod) {// do something } 分析: 1.此种…...
English Learning - L2-2 英音地道语音语调 2023.02.23 周四
English Learning - L2-2 英音地道语音语调 2023.02.23 周四查音标的工具怎么练习效果好准备工作大小声练习大元音开口度的对比舌位对比复习后元音 /ɑː/ /ɔː/ /uː//ɑː//ɔː//uː/前元音 /iː/发音技巧对应单词的发音对应句子的发音常见的字母组合中元音 /ɜː/发音技巧…...
java:线程等待与唤醒 - Object的wait()和notify()
java:线程等待与唤醒 - Object的wait()和notify() 1 前言 java使用Object类的wait()和notify()方法,可以实现线程等待和唤醒(Object类为所有类的父类,即所有类天然具有线程等待和唤醒的方法,一般使用Object类的wait(…...
实现弹窗功能并修改其中一个系数
把鼠标放在number-info上面,会是一个delon/chart的类库,可以在NG-ALAIN上找到阅读NG ALAIN的图表,以及number-info样式,数据文本 它拥有[title] [subtitle]两个可以是TemplateRef类型的,而template可以在里面放一些东西,比如按钮,所以可以放一个修改按钮 这里刚开始把template放…...
vue-draggable浏览器拖拽event事件对象拖动时 DragEvent path undefined
场景: 在做组件拖拽过程中,需要获取到触发元素冒泡过程中的所有元素,所以使用了event.path属性。在Chrome下正常运行,但是在FireFox下测试时发现,完犊子,失效了,通过问题排查,发现了…...
【云原生】搭建k8s高可用集群—20230225
文章目录多master(高可用)介绍高可用集群使用技术介绍搭建高可用k8s集群步骤1. 准备环境-系统初始化2. 在所有master节点上部署keepalived3.1 安装相关包3.2 配置master节点3.3 部署haproxy错误解决3. 所有节点安装Docker/kubeadm/kubelet4. 部署Kuberne…...
LeetCode121_121. 买卖股票的最佳时机
LeetCode121_121. 买卖股票的最佳时机 一、描述 给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最…...
收割不易,五面Alibaba终拿Java岗offer
前言 前段时间有幸被阿里的一位同学内推,参加了阿里巴巴Java岗位的面试,本人19年双非本科软件工程专业,目前有一年半的工作经验,面试前就职于一家外包公司。如果在自己本人拿到offer之前,如果有人告诉我一年工作经验可…...
【离线数仓-4-数据仓库设计-分层规划构建流程】
离线数仓-4-数据仓库设计-分层规划&构建流程离线数仓-4-数据仓库设计-分层规划&构建流程1.数据仓库分层规划2.数据仓库构建流程1.数据调研1.业务调研2.需求分析3.总结2.明确数据域3.构建业务总线矩阵&维度模型设计4.明确统计指标1.指标体系相关概念1.原子指标2.派生…...
SQL零基础入门学习(十一)
SQL零基础入门学习(十) SQL NOT NULL 约束 NOT NULL 约束强制列不接受 NULL 值。 NOT NULL 约束强制字段始终包含值。这意味着,如果不向字段添加值,就无法插入新记录或者更新记录。 下面的 SQL 强制 “ID” 列、 “LastName” …...
第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
从零实现富文本编辑器#5-编辑器选区模型的状态结构表达
先前我们总结了浏览器选区模型的交互策略,并且实现了基本的选区操作,还调研了自绘选区的实现。那么相对的,我们还需要设计编辑器的选区表达,也可以称为模型选区。编辑器中应用变更时的操作范围,就是以模型选区为基准来…...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...
高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
