APP优化 —— MMAP内存映射

news2024/9/27 7:16:53

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读写流程

  1. 用户进程发起文件数据的读请求
  2. 内核通过查找进程文件符表,定位内核已打开文件集上的文件信息,从而找到文件inode
  3. inode在address_space上查找要请求的文件页是否已缓存在页缓存中
  4. 如已在缓存页中,则直接返回这片文件页上的内容
  5. 如不在缓存页上,就会引发缺页中断。 当发生缺页中断时,内核则调用nopage函数把所缺的页从磁盘装入到内存内核中及Page Cache中。接着再发起读页面过程,从而将数据从页缓存中拷贝到用户空间中

特点:

常规文件操作为了读写效率和保护磁盘,使用了页缓存机制 页缓存处在内核空间中,不能直接被用户进程直接寻址,需要将数据从页缓存中拷贝到主内存

mmap读写流程

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

特点:

  1. 用户空间与内核空间磁盘块通过映射直接交互,不在间接通过页缓存。
  2. 文件读写操作跨过了页缓存,数据拷贝次数减少为只需一次
  3. 借助硬盘的大空间,对于大规模数据的读写避免对页内存空间大小的依赖,提高操作效率。

mmap数据读写的性能提升就在于对数据的读写拷贝次数,mmap只需要一次系统调用(一次拷贝),后续操作不需要系统调用。并且访问的数据不需要在page cache和用户缓冲区之间拷贝。

mmap读写优势

  1. 对文件的读取操作跨过了页缓存,减少了数据的拷贝次数,用内存读写取代I/O读写,提高了文件读取效率。
  2. 实现了用户空间和内核空间的高效交互方式。两空间的各自修改操作可以直接反映在映射的区域内,从而被对方空间及时捕捉。
  3. 提供进程间共享内存及相互通信的方式。不管是父子进程还是无亲缘关系的进程,都可以将自身用户空间映射到同一个文件或匿名映射到同一片区域。从而通过各自对映射区域的改动,达到进程间通信和进程间共享的目的。

如果进程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状态。

  1. 内存分配

我们使用c库的malloc申请内存,malloc的分配内存有两个系统调用,一个brk,另一个就是mmap。

mmap不仅可以映射文件,也可以映射内存,当mmap使用的flag是MAP_ANONYMOUS,称为建立匿名映射,此时会忽略参数fd,不涉及文件,而且映射区域无法和其他进程共享。匿名映射存储的数据就是在物理内存上,不属于任何文件。malloc分配内存底层就是用mmap的匿名映射来操作的。

  1. 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将数据同步回磁盘。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微信小程序(起步)

微信小程序1、微信小程序--起步1.1 小程序简介1.2 小程序构成1.3 小程序的宿主环境1.4 协同工作和发布1、微信小程序–起步 1.1 小程序简介 小程序与普通网页开发的区别 运行环境不同 网页运行在浏览器中&#xff0c;小程序运行在微信环境中 API不同 小程序无法调用DOM和BOM…

【unity3d】1 界面 贴图 渲染 相机

一 学习背景 暴雪国服停运后&#xff0c;没有星际玩要死力 玩了一段时间[原神]感觉这个世界观和机制设定有点牛笔&#xff0c;米哈游怎么不像[魔兽世界-魔兽争霸]的关系那样&#xff0c;做个[原神争霸]捏&#xff0c;不如自己做一个耍耍 二 unity3d安装 1 官网&#xff0c;直…

Kotlin DSL 实战

1. 前言Kotlin 是一门对 DSL 友好的语言&#xff0c;它的许多语法特性有助于 DSL 的打造&#xff0c;提升特定场景下代码的可读性和安全性。本文将带你了解 Kotlin DSL 的一般实现步骤&#xff0c;以及如何通过 DslMarker &#xff0c; Context Receivers 等特性提升 DSL 的易用…

GORM-GEN快速上手

目录 1.什么是 GEN 2.GEN特性 3.快速使用GEN 3.1. 下载 3.2. 生成 4. 基础查询 5. 自定义 SQL 查询 6.demo源码 1.什么是 GEN 官方文档&#xff1a;Gen Guides | GORM - The fantastic ORM library for Golang, aims to be developer friendly. GEN 项目地址&#xf…

「mysql是怎样运行的」第19章 从猫爷被杀说起---事务简介

「mysql是怎样运行的」第19章 从猫爷被杀说起—事务简介 文章目录「mysql是怎样运行的」第19章 从猫爷被杀说起---事务简介[toc]一、事务的起源概述原子性(Atomicity)隔离性(Isolation)一致性(Consistency)持久性(Durability)二、事务的概念一、事务的起源 概述 对于大部分程…

android UI优化的基本原理和实战方法

任何Android应用都需要UI跟用户交互.UI是否好坏更是直接影响到用户的体验.如今UI的优化视乎是应用开发中一个绕不过去的话题。所以本篇文章小编带大家全面了解Android ui优化的主要知识和优化方法。 一、UI优化 UI优化知识点主要分为三部分&#xff1a; 第一部分&#xff0c…

Linux简单介绍(基本涵盖日常使用到的各种shell知识点)

文章目录shell基础认知1. shell语言2. 脚本执行方式3. 快捷键4. 通配符5. 命令后跟的选项6. 逻辑运算 && ||7. 算术运算&#xff08;equal&#xff0c;great&#xff0c;less&#xff09;8. 目录或文件意义9. 规则10. vimshell脚本常规内容解释1. set -ex2. set -o pip…

Google Brain新提出的优化器“Lion”,效果要比Adam(W)更好

Google Brain新提出的优化器“Lion”&#xff0c;效果要比Adam(W)更好 论文地址&#xff1a;https://arxiv.org/abs/2302.06675代码地址&#xff1a;https://github.com/google/automl/blob/master/lion/lion_pytorch.py 1 简单、内存高效、运行速度更快 与 AdamW 和各种自适…

量子计算对网络安全的影响

量子计算的快速发展&#xff0c;例如 IBM 的 Quantum Condor 处理器具有 1000 个量子比特的容量&#xff0c;促使专家们宣称第四次工业革命即将实现“量子飞跃”。 量子计算机的指数处理能力已经受到政府和企业的欢迎。 由于从学术和物理原理到商业可用解决方案的不断转变&am…

Spark Explain:查看执行计划

Spark SQL explain 方法有 simple、extended、codegen、cost、formatted 参数&#xff0c;具体如下 目录一、基本语法二、执行计划处理流程三、具体案例一、基本语法 从 3.0 开始&#xff0c;explain 方法有一个新的 mode 参数&#xff0c;指定执行计划展示格式 只展示物理执…

都2023年了,竟然还有人问网络安全怎么入门?

工作一直忙碌&#xff0c;偶然翻了一下知乎&#xff0c;都2022年了&#xff0c;相关网课这么多了&#xff0c;还有人不知道怎么学习网络安全&#xff0c;不了解也就算了&#xff0c;竟然还有一批神仙也真敢回答&#xff0c;对这个行业了解各一知半解就当做这些萌新的启蒙老师了…

UDP与TCP协议

目录 UDP协议 协议报头 UDP协议特点&#xff1a; 应用场景&#xff1a; TCP TCP协议报头 确认应答机制 理解可靠性 超时重传机制 连接管理机制 三次握手&#xff1a; 四次挥手&#xff1a; 滑动窗口 如何理解缓冲区和滑动窗口&#xff1f; 倘若出现丢包&#xf…

05 DC-AC逆变器(DCAC Converter / Inverter)简介

文章目录0、概述逆变原理方波变换阶梯波变换斩控调制方式逆变器分类逆变器波形指标1、方波变换器A 单相单相全桥对称单脉冲调制移相单脉冲调制单相半桥2、方波变换器B 三相180度导通120度导通&#xff08;线、相的关系与180度相反&#xff09;3、阶梯波逆变器独立直流源二极管钳…

Esxi NAT网络搭建

前言 本文主要讲述如何在Esxi上只有一个公网IP情况下,实现内部虚拟机上网,以及外部对内部服务的访问,以及外网通过vpn访问内网; 环境 Esxi 6.7iKuai8 3.6.13OpenVPN 2.6一、创建虚拟路由 1.1 目的 虚拟路由,也就是常说的软路由;只有一个外网IP情况下,其他虚拟机需要上…

LeetCode刷题系列 -- 429. N 叉树的层序遍历

给定一个 N 叉树&#xff0c;返回其节点值的层序遍历。&#xff08;即从左到右&#xff0c;逐层遍历&#xff09;。树的序列化输入是用层序遍历&#xff0c;每组子节点都由 null 值分隔&#xff08;参见示例&#xff09;。示例 1&#xff1a;输入&#xff1a;root [1,null,3,2…

【每日阅读】JS知识(三)

var声明提升 js是一个解释性语言类型&#xff0c;预解析就是在执行代码之前对代码进行通读 var关键字是&#xff0c;在内存中声明一个变量名 js在代码执行之前 会经历两个环节 解释代码 和执行代码 声明式函数 内存中 先声明一个变量名是函数 这个名代表的是函数 乘法表 // for…

IP、ICMP、TCP和UDP校验和计算

一. 前言 计算网络数据包的校验和是机器自动完成&#xff0c;不需要手动计算。但是正因为如此&#xff0c;我们往往不会去深究校验和到底是怎么计算的&#xff0c;留下这一块盲区。虽然书上有大致介绍计算的方法&#xff0c;但是&#xff0c;“纸上得来终觉浅&#xff0c;绝知此…

二叉树——验证二叉搜索树

验证二叉搜索树 链接 给你一个二叉树的根节点 root &#xff0c;判断其是否是一个有效的二叉搜索树。 有效 二叉搜索树定义如下&#xff1a; 节点的左子树只包含 小于 当前节点的数。 节点的右子树只包含 大于 当前节点的数。 所有左子树和右子树自身必须也是二叉搜索树。 …

【Proteus仿真】【51单片机】粮仓温湿度控制系统设计

文章目录一、功能简介二、软件设计三、实验现象联系作者一、功能简介 本项目使用Proteus8仿真51单片机控制器&#xff0c;使用声光报警模块、LCD1602显示模块、DHT11温湿度模块、继电器模块、加热加湿除湿风扇等。 主要功能&#xff1a; 系统运行后&#xff0c;LCD1602显示传…

LeetCode 144. 二叉树的前序遍历

144. 二叉树的前序遍历 难度&#xff1a;easy\color{Green}{easy}easy 题目描述 给你二叉树的根节点 rootrootroot &#xff0c;返回它节点值的 前序 遍历。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,2,3]示例 2&#xff1a; 输入&#…