mmap 创建共享内存映射

news2024/12/25 8:56:03

所谓内存映射指的是 让一个磁盘文件与内存中的一个缓冲区相映射,进程访问这块内存时,就等同于访问文件对应映射部分,不必再调用 read / write 。

我们可以使用mmap函数来建立内存和文件某一部分的映射关系。


目录

一、共享内存映射的创建 / 释放

1、创建共享内存映射:mmap

2、释放共享内存映射:munmap

二、mmap使用及其注意事项

1、mmap使用

(1) 打开文件

(2) mmap建立映射

(3) 通过映射向文件写入内容

(4) 完整代码

2、mmap使用注意事项

(1) 映射区只要建立成功,文件可以立即关闭

(2) 映射的文件大小必须大于0,否则会报总线错误

(3) 文件偏移量必须为0或者4K的整数倍

(4) 映射空间大小可以大于文件大小,但要注意不要访问区外部分

(5) 设置的映射空间大小 ≠ 实际分配的映射空间大小


一、共享内存映射的创建 / 释放

1、创建共享内存映射:mmap

mmap 函数的作用是创建共享内存映射。mmap函数的参数较多,几乎每一个参数都有注意事项,下面介绍的重点是mmap函数的参数。

(1) addr

用户可以手动指定要映射的内存地址,一般设置为NULL,让OS自动选择合适的内存地址,如果最后映射建立成功,mmap会返回内存中映射区的首地址。

(2) length

为内存中映射地址空间分配的字节数(length > 0)。这里分为了两种情况:

  • length > 文件映射部分大小
  • length < 文件大小

当 length < 文件映射部分大小 时,文件有一部分无法映射到内存。

当 length > 文件映射部分大小 时,有一部分无法映射到文件,这就意味着,即便向这部分内存写入内容,也不会反馈给文件。

因此,一般建议设置的映射空间大小直接和文件大小保持一致。文件大小的计算可以使用lseek函数。

// 起始偏移量为0,将文件指针移动到末尾(SEEK_END)
// 返回的结果就是 文件指针相对于起始位置的字节数
int size = lseek(fd, 0, SEEK_END);

 

(3) prot

指定内存映射空间的访问权限。其实就是要以何种形式来访问这块映射空间,如可读、可写、可执行等,可选值如下:

可选值含义
PROT_READ可读
PROT_WRITE可写
 PROT_EXEC可执行
PROT_NONE不可访问

(4) flags

指定内存映射空间的映射方式。可以是共享,代表其他进程可以看到;可以是私有,代表其他进程看不到;也可以是匿名,一般用于有血缘关系之间的进程。可选值如下:

可选值含义
MAP_SHARED共享
MAP_PRIVATE私有
MAP_ANONYMOUS匿名

注意: MAP_SHARED 和  MAP_PRIVATE必选其一

(5) fd

指定要映射的文件。当一个文件被成功打开的时候,就会有一个文件描述符来唯一的指向该文件。如果是匿名映射,填 -1

:为什么建立内存映射需要打开文件?

:在创建映射区的过程中,隐藏着一次对映射文件的读操作,目的是将部分文件内容读取到映射区。(读取多少,取决于偏移量的设置)

(6) offset

表示映射文件的偏移量。设置为0表示从头开始映射。当你向映射区写入内容的时候,其实是向文件的起始映射位置开始写入,而不是从文件起始位置开始写入。

映射部分:向映射区写入的内容,会映射到文件的对应部分

剩余部分:内存是以页为单位进行分配的,一页大小是4K,映射区的大小如果小于4K,剩下没有映射的就是“剩余部分”,访问该部分的时候,不会有任何问题,因为这块内存还在一页的范围里。但是你向该部分写入的内容,不会映射到文件,因为在文件里不存在对应的映射区域。

区外部分:该部分是内存没有分配给你的,访问这部分会报总线错误。

(6) 返回值

 映射创建成功,返回创建映射区的首地址,失败返回 MAP_FAILED(((void *) -1)),设置errno值

2、释放共享内存映射:munmap

释放共享内存映射的时候,需要提供映射区的首地址,以及你手动分配的大小,注意这里要填的不是实际分配的大小,而是 mmap 第二个参数填入的值。

 

二、mmap使用及其注意事项

1、mmap使用

(1) 打开文件

映射文件必须以读写 (O_RDWR) 的形式打开,同时该文件的大小必须要大于0,否则会出现

int fd = open("./log.txt", O_RDWR);
if(fd < 0)
{
    perror("open");
    return -1;
}

(2) mmap建立映射

针对mmap 的各个参数,设置如下:

  • 第一个参数设为NULL,交由OS来分配内存
  • 第二个参数设为文件大小
  • 第三个参数设为可写 PROT_WRITE
  • 第四个参数设为共享 MAP_SHARED
  • 第五个参数填入上面得到的文件描述符
  • 第六个参数设为0,代表从文件起始位置开始映射
int len = lseek(fd, 0, SEEK_END);
void* addr = mmap(NULL, len, PROT_WRITE, MAP_SHARED, fd, 0);
if(addr == MAP_FAILED)
{
    perror("mmap");
    return -1;
}

(3) 通过映射向文件写入内容

我们向内存映射空间中写入一个字符串,然后看一下文件中是否有对应的字符串

const char* str = "hello, world";
memcpy(addr, str, strlen(str));

(4) 完整代码

#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>

int main(){
	int fd = open("./log.txt", O_RDWR);
	if(fd < 0)
	{
		perror("open");
		return -1;
	}

	int len = lseek(fd, 0, SEEK_END);
	void* addr = mmap(NULL, len, PROT_WRITE, MAP_SHARED, fd, 0);
	if(addr == MAP_FAILED)
	{
		perror("mmap");
		return -1;
	}

	const char* str = "hello, world";
	memcpy(addr, str, strlen(str));
	return 0;
}

 

2、mmap使用注意事项

(1) 映射区只要建立成功,文件可以立即关闭

在创建映射区的过程中,隐藏着一次对映射文件的读操作,目的是将部分文件内容读取到映射区。映射建立成功也就意味着读写完毕,此时只需要向内存映射中写入即可。

 

(2) 映射的文件大小必须大于0,否则会报总线错误

如果映射文件的大小为0,那就说明我们无论怎么向映射里写入内容,都不会反馈到文件中,那就失去了映射的意义。

(3) 文件偏移量必须为0或者4K的整数倍

(4) 映射空间大小可以大于文件大小,但要注意不要访问区外部分

映射空间的大小可以大于文件大小,只是有一部分空间无法映射到文件,向这部分空间写入的内容不会反馈给文件。

(5) 设置的映射空间大小 ≠ 实际分配的映射空间大小

实际在分配内存的时候,是以页为单位进行分配的,每页大小是4K,实际大小会根据文件大小来定。并不是你设置了多少,内存就给你分配多少。

如果文件大小是2000字节,即便mmap第二个参数填入的是6000,映射空间的大小就是 4K,此时需要注意,超出4K部分属于区外部分,访问区外部分会报总线错误。

如果文件大小是6000字节,大于了一页的大小,此时就会分配两页大小,映射空间大小就是8K。

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

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

相关文章

代码审计-3 文件包含漏洞

文章目录代码审计-文件包含漏洞文件包含漏洞种类当检测到目标存在文件包含漏洞时可以怎么利用文件包含中php可使用的协议PHPCMS V9.6.3后台文件包含漏洞后台路由分析漏洞寻找代码审计-文件包含漏洞 文件包含漏洞种类 当检测到目标存在文件包含漏洞时可以怎么利用 文件包含中php…

npm run dev和npm run serve

npm run dev和npm run serve目录概述需求&#xff1a;设计思路实现思路分析1.npm install命令2.package.json3.npm run serve参考资料和推荐阅读Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,make …

redis基础4——RDB持久化、AOF持久化全面深入解读

文章目录一、redis持久化机制1.1 持久化的背景1.2 两种持久化概念1.2.1 快照方式&#xff08;RDB&#xff09;1.2.2 文件追加方式&#xff08;AOF&#xff09;1.3 rdb持久化&#xff08;Redis Database&#xff09;1.3.1 快照原理1.3.2 触发机制1.3.2.1 手动触发1.3.2.1.1 save…

最常用的python开发工具

有哪些值得推荐的 Python 开发工具 推荐5个非常适合Python小白的开发工具&#xff1a;1、Python TutorPython Tutor是由Philip Guo开发的一个免费教育工具&#xff0c;可帮助开发者攻克编程学习中的基础障碍&#xff0c;理解每一行源代码在程序执行时在计算机中的过程。 通过…

CentOS8克隆虚拟机修改IP,错误:未知的连接 “ens160“

关于CentOS8该如何克隆与修改IP&#xff0c;并设置成静态IP的方法&#xff0c;可以参考我的另一篇文章&#xff0c;我也是一直这么做的。 CentOS8拷贝虚拟机、修改ip、主机 但是最近我再使用我的这篇文章克隆虚拟机的时候&#xff0c;竟然报错了&#xff0c;本来想删除掉克隆…

2023年天津农学院专升本专业课报名、确认缴费及准考证打印流程

天津农学院2023年高职升本科专业课考试 报名、确认缴费及准考证打印操作流程 一、报名操作流程 1. 阅读报名注意事项 请考生于2022年12月5日9点—12月10日12点登录报名系统 http://gzsb.tjau.edu.cn&#xff0c;请认真阅读报名注意事项。2.报名登录 点击“报名”菜单后进入报名…

LeetCode 374. 猜数字大小

&#x1f308;&#x1f308;&#x1f604;&#x1f604; 欢迎来到茶色岛独家岛屿&#xff0c;本期将为大家揭晓LeetCode 374. 猜数字大小&#xff0c;做好准备了么&#xff0c;那么开始吧。 &#x1f332;&#x1f332;&#x1f434;&#x1f434; 一、题目名称 LeetCode 374.…

2023最新SSM计算机毕业设计选题大全(附源码+LW)之java高校辅导员工作管理系统82aub

对于即将毕业或者即将做课设的同学而言&#xff0c;由于经验的欠缺&#xff0c;面临的第一个难题就是选题&#xff0c;确定好题目之后便是开题报告&#xff0c;如果选题首先看自己学习那些技术&#xff0c;不同技术适合做不同的产品&#xff0c;比如自己会些简单的Java语言&…

【圣诞文】用python带你体验多重花样圣诞树

前言 大家早好、午好、晚好吖 ❤ ~ 在圣诞要来临的前夕&#xff0c;我们来出一起圣诞特辑吧 &#xff08;虽说可能有一丢丢早&#xff0c;但是等要来了在准备就来不及了呀~&#xff09; 圣诞节要素 1、圣诞袜&#xff0c;最早以前是一对红色的大袜子&#xff0c;大小不拘。 …

Spring异步任务async介绍与案例实战

关于spring异步任务 简单地说&#xff0c;用Async注释bean的方法将使其在单独的线程中执行。换句话说&#xff0c;调用者不会等待被调用方法的完成。利用spring提供的注解即可简单轻松的实现异步任务处理。 默认线程池问题 Spring 异步任务默认使用 Spring 内部线程池 Simpl…

网页自动点赞

进入网页版QQ空间 ,在开发者模式下创建脚本 var x5,y10;function autoClick(){yy5;var zandocument.getElementsByClassName(item qz_like_btn_v3);for(var i0;i<zan.length;i){if(zan[i].attributes[6].valuelike){zan[i].firstChild.click();}};window.scrollBy(x,y);}win…

LC118原厂直流驱动芯片 SOP-8

直流驱动芯片 LC118 SOP-8 电机驱动电路 马达驱动IC 马达驱动IC LC118的描述&#xff1a; LC118 是为专门为低电压下工作的系统而设计的单通道玩具直流电机驱动集成电路。它具有 H桥驱动器, 采用导通电阻非常小的P-MOS和N-MOS功率晶体管作为开关管&#xff0c;可在瞬间提供大电…

CMake中target_link_libraries的使用

CMake中的target_link_libraries命令用于指定链接给定目标和/或其依赖项时要使用的库或标志。来自链接库目标的使用要求将被传播(propagated)。目标依赖项的使用要求会影响其自身源代码的编译。其格式如下&#xff1a; target_link_libraries(<target> ... <item>…

用Rust写一个链表,非常详细,一遍看懂

前言 在Rust里写一个链表可不是一件容易的事&#xff0c;涉及到很多的知识点&#xff0c;需要熟练掌握之后才能写出一个不错的链表。这篇文章主要介绍了如何写一个Rust链表&#xff0c;并且补充了涉及到的很多的额外知识点&#xff0c;尤其是所有权问题。 首先&#xff0c;你需…

人工智能内容生成元年—AI绘画原理解析

AIGC体验生成一、背景 2022年AIGC&#xff08;AI生成内容&#xff09;焕发出了勃勃生机&#xff0c;大有元年之势&#xff0c;技术与应用迭代都扎堆呈现。在各种新闻媒体处可以看到诸多关于学术前沿研究&#xff0c;以及相应落地的商用案例。可谓出现了现象级的学术-商业共振。…

phpbugs代码审计第三题多重加密答案错误

phpbugs多重加密 这题官方给的答案是错的&#xff0c;网上给的也是错的&#xff0c;麻烦别直接拿给的答案来抄好吗&#xff1f;就想纠正一下别误导别人了 源码如下: <?phpinclude common.php;$requset array_merge($_GET, $_POST, $_SESSION, $_COOKIE);//把一个或多个…

安卓期末大作业——售票APP源码和设计报告

大作业文档 项目名称&#xff1a;售票APP专业&#xff1a;班级&#xff1a;学号&#xff1a;姓名&#xff1a; 目 录 目录 一、项目功能介绍3二、项目运行环境31、开发环境32、运行环境33、是否需要联网3三、项目配置文件及工程结构31、工程配置文件32、工程结构目录4四、项…

【C语言 数据结构】串 - 顺序

文章目录串 - 顺序一、串的表示及实现1.1 串的概念1.2 串的初始化1.3 复制串1.4 串的判空1.5 串的比较1.6 串的长度1.7 清空串1.8 串的拼接1.9 串的截取1.10 插入子串1.11 串的打印二、串的应用2.1 串的模式匹配 - 基本操作2.2 串的模式匹配 - BF2.3 串的模式匹配 - KMPnext数组…

【学习笔记77】ajax的函数封装

一、封装分析 &#xff08;一 &#xff09;封装方案 1、回调函数方式 将来使用的时候, 可能会遇到回调地狱 2、promise方式 效果不会有变化, 而且还能和 async/await 一起使用 &#xff08;二&#xff09;函数的参数 请求方式: method > 默认值 get请求地址: url > 必填…

Android开发——Jetpack Compose的使用

Android开发——Jetpack Compose的使用什么是Jetpack ComposeJetpack Compose带来的变化Jetpack Compose的两种运用方法将Jetpack Compose 添加到现有项目1.gradle 配置2.使用Kotlin-Gradle 插件3. 添加依赖项创建一个新的支持Jetpack Compose的项目1.创建一些简单应用定义可组…