mmap的使用与底层原理

mmap(Memory Map,内存映射)是一种将文件或其它对象映射到进程虚拟地址空间的方法。通过 mmap,程序可以把文件的某一部分当作连续的内存来直接读写,而不需要再调用传统的 read 或 write 等 I/O 系统调用。

使用

mmap的函数签名如下:

cpp 复制代码
void* mmap(
    void* addr,
    size_t length,
    int prot,
    int flags,
    int fd,
    off_t offset
);

六个参数分别是

txt 复制代码
addr    希望映射到哪个虚拟地址,一般传 nullptr
length  映射多少字节
prot    这块内存允许你做什么:读 / 写 / 执行
flags   这块映射怎么和文件交互:私有 / 共享 等
fd      文件描述符
offset  从文件哪个位置开始映射

重点讲讲prot和flag的区别

prot控制内对这块内存做什么,常见值包括PROT_READ、PROT_WRITE、PROT_EXEC、PROT_NONE

分别控制可以对返回的void*进行什么类型的操作,读/写/可执行/什么都不允许

flags控制内存与文件的映射关系MAP_PRIVATE、MAP_SHARED、MAP_ANONYMOUS

比如private,表示对内存的修改不会映射到文件,相当于是私有的,shared则是对内存的修改会映射到文件,别的进程也可以看见。当参数是MAP_ANONYMOUS时,表示不需要文件进行映射,这个一般用于父子进程之间本来就有一份进程地址空间的拷贝。

offset一般时page_size的倍数

原理

mmap 不是"把文件读进内存",而是"在进程虚拟地址空间里建立一段映射关系,让这段虚拟地址背后对应文件页或匿名内存页"

mmap 干的事情,本质就是操作虚拟地址与物理页的映射关系。

与read的一个直观的对比如下

cpp 复制代码
char buffer[4096];
read(fd, buffer, 4096); //这里经历了一次拷贝从文件->page cache到用户态buffer的拷贝

void* p = mmap(...);//这里没经历拷贝就建立了映射关系
p[offset]; //读写时发生缺页中断,按需加载,少一次到用户态的拷贝

所以mmap一开始只是建立一个映射,并不会立马加载数据

prot = prot_shared时,便是两个进程的虚拟地址映射到同一个物理页,写时标记该页为脏页,之后会修改文件,同样也可以主动调用::msync(...)落盘,

prot = prot_priate时,进程正常读没有问题,写时会触发写时复制,讲物理页复制到一个新的匿名页,并在其上做对应的修改,于是其他映射到物理页的进程看不到修改

prot = MAP_ANONYMOUS | MAP_SHARED时,可以和fork配合,先mmap,简历映射,再fork,此时子进程把父进程的虚拟地址空间布局 继承过去且由于是share模式,此时虽然是匿名页,且父子进程虽然是两个不同的进程,且有自己的页表,但这两个页表项可以指向同一个物理页。

以上是我个人一些浅显的理解,以后再补充吧

相关推荐
木卫二号Coding3 小时前
推荐Linux统计文件大小并操作删除工具-ncdu
linux·运维·服务器
AC赳赳老秦4 小时前
采集行为合规自检:OpenClaw 自动校验 robots 协议与采集频率,规避违规采集风险
java·开发语言·c++·python·php·deepseek·openclaw
无名猿4 小时前
C++ 查找算法:std::find 与容器成员 find 的性能差距
c++·性能优化·stl·标准库
程序猿编码5 小时前
工业视觉多任务方案:可编程梯度信息视觉框架,训练评估 + C++ 部署完整实战
开发语言·c++·视觉·推理引擎
zhangrelay5 小时前
机械臂末端规划智能模型的误区演示
linux·笔记·学习·ubuntu·ros2
朝朝辞暮i6 小时前
C++ 第 21 课:struct —— 把一组相关数据打包在一起
开发语言·c++·算法
SHARK_pssm7 小时前
【C++——类和对象(下)】
开发语言·c++·经验分享·笔记
Ivanqhz7 小时前
正余弦位置编码(Sinusoidal Positional Encoding)
java·linux·数据库
H.莓飛7 小时前
【数据结构】队列
linux·数据结构·centos
汉克老师7 小时前
GESP2026年9月认证C++二级( 第一部分选择题(1~7题)精讲
c++·gesp·小学生·学c++编程