【Linux】mmap文件内存映射

article/2025/6/19 6:00:05

📝前言:

这篇文章我们来讲讲Linux——mmap

  1. mmap介绍
  2. mmap接口介绍
  3. mmap使用示例

🎬个人简介:努力学习ing
📋个人专栏:Linux
🎀CSDN主页 愚润求学
🌄其他专栏:C++学习笔记,C语言入门基础,python入门基础,C++刷题专栏


这里写目录标题

  • 一,mmap介绍
    • 1. 基本介绍
    • 2. mmap的优势
  • 二,接口介绍
    • 1. mmap建立映射
    • 2. munmap取消映射
  • 三,使用示例
    • 1. 写入映射
    • 2. 读取映射
    • 3. 简单模拟实现malloc

一,mmap介绍

1. 基本介绍

  • 允许用户空间程序将文件或设备的内容直接映射到进程的虚拟地址空间中。(直接建立虚拟内存到文件页缓存的映射关系
    在这里插入图片描述

2. mmap的优势

通过 系统调用mmap ,程序可以高效地访问文件数据,而无需通过传统的 readwrite 系统调用进行数据的复制

具体来说:

  • 传统的readwrite分为两步(下面以write为例)

    • 第一步:用户态空间缓冲区 → 内核页缓冲区(其实就是内核文件缓冲区)
    • 第二步:内核页缓冲区 → 磁盘
  • 使用mmap

    • 映射阶段:内核将文件映射到进程的虚拟地址空间,但物理内存尚未分配(讲页表的时候提到的:延迟申请,当真正访问阶段需要的时候才缺页中断分配)
    • 修改数据:进程直接修改映射的内存(相当于直接修改内核的页缓存),无需调用 write,也无用户态到内核态的数据拷贝

注意:当内核页缓存修改好了,我们就认为改好了,我们不关心内核缓冲区到磁盘的刷新这一过程(复杂)

二,接口介绍

当我们建立好映射以后,就可以直接对“开辟”的空间进行操作(虚拟地址)
我们对虚拟地址的操作,都是直接修改映射的内存。

1. mmap建立映射

头文件<sys/mman.h>

函数原型

void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);

参数说明

  • addr:建议的映射起始地址(通常设为 NULL,由内核自动选择)
  • length:映射区域的长度(必须是页大小(4 KB)的整数倍,如 4096 字节)
  • prot:映射区的内存保护模式选项(用|链接)
    • PROT_READ:映射区可读
    • PROT_WRITE:映射区可写
    • PROT_EXEC:映射区可执行
    • 注意:映射权限必须 <= 文件打开权限
  • flags:映射类型(如 MAP_SHAREDMAP_PRIVATE
    • MAP_PRIVATE:创建⼀个私有映射。对映射区域的修改不会反映到底层文件中。(即:修改仅对当前进程有效(写时复制,类似 fork
    • MAP_SHARED:创建⼀个共享映射。对映射区域的修改会反映到底层文件中(即:修改会同步到文件,其他进程可见)
    • MAP_ANONYMOUS:指定要创建⼀个匿名内存映射
  • fd:文件描述符(匿名映射时设为 -1
  • offset 文件偏移量(开始映射的位置相较于0位置处的偏移)(必须是页大小的整数倍)

返回值

  • 成功:返回映射区的起始地址(虚拟地址)
  • 失败:返回(void*) -1 或者 MAP_FAILED(等效的)

注意

  • 映射的要是一个已经打开的文件!
  • 文件大小为 0 的文件无法映射,需要先调整文件大小
    • ftruncate(fd, SIZE)(会把文件的内容全部初始化成\0
  • 映射的长度如果 > 文件的大小,则可能导致未定义行为
  • 因为mmap需要读取文件元数据(如大小):所以,即使你只需要写入权限,也需要在open文件的时候赋予读权限

2. munmap取消映射

函数原型

int munmap(void *addr, size_t length);

参数介绍

  • addr:映射空间的起始地址
  • length:空间长度(大小)

返回值
- 成功:0
- 错误:-1(错误码会被设置)

三,使用示例

1. 写入映射

#include <iostream>
#include <cstdio>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>#define FILENAME "log.txt"
#define SIZE 1024int main()
{// 打开文件int fd = open(FILENAME, O_RDWR | O_APPEND | O_CREAT, 0666);if(fd < 0){perror("open");return 1;}// 调整文件大小ftruncate(fd, SIZE);// 建立映射char* mmap_addr = (char*)mmap(nullptr, SIZE, PROT_WRITE, MAP_SHARED, fd, 0);if(mmap_addr == MAP_FAILED){perror("mmap");return 2;}// 写入操作for(int c = 'a', i = 0; c <= 'z'; c++, i++){mmap_addr[i] = c;}// 取消映射munmap(mmap_addr, SIZE);// 关闭文件close(fd);std::cout << "写入映射完毕" << std::endl;return 0;
}

运行结果:
在这里插入图片描述

2. 读取映射

#include <iostream>
#include <cstdio>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>#define FILENAME "log.txt"int main()
{// 打开文件int fd = open(FILENAME, O_RDONLY);if(fd < 0){perror("open");return 1;}struct stat st; // struct stat 类型的结构体用于记录文件的属性fstat(fd, &st); // 获得fd对应的文件的结构体// 建立映射char* mmap_addr = (char*)mmap(nullptr, st.st_size, PROT_READ, MAP_SHARED, fd, 0);if(mmap_addr == MAP_FAILED){perror("mmap");return 2;}// 读取操作std::cout << mmap_addr << std::endl;// 取消映射munmap(mmap_addr, st.st_size);// 关闭文件close(fd);std::cout << "读取映射完毕" << std::endl;return 0;
}

运行效果:
在这里插入图片描述

3. 简单模拟实现malloc

在malloc里,对应大块的内存通常是使用mmap来分配的,而对应小块的内存,是用brk来分配的

这里要再介绍一个flags选项:MAP_ANONYMOUS

  • MAP_ANONYMOUS:指定要创建⼀个匿名内存映射
  • 当使使用MAP_ANONYMOUS 标志时, mmap 会分配⼀段不与任何⽂件相关联的内存区域(即这段内存没有⽂件作为其后端存储)。
  • 这种类型的映射通常用于需要分配私有内存的场景,例如进程内部的内存分配

下面用mmap简单模拟实现一下malloc

#include <iostream>
#include <cstdio>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>#define SIZE 1024void* MyMalloc(int size)
{// 建立映射(匿名映射)void* mmap_addr = mmap(nullptr, size, PROT_WRITE | PROT_READ, MAP_SHARED | MAP_ANONYMOUS, -1, 0);if(mmap_addr == MAP_FAILED){perror("mmap");exit(EXIT_FAILURE);}return mmap_addr;
}void Myfree(void* mmap_addr, int size)
{if(munmap(mmap_addr, size) == -1){perror("munmap");exit(EXIT_FAILURE);}
}int main()
{char* ptr = (char*)MyMalloc(SIZE);// 写入操作for(int c = 'a', i = 0; c <= 'z'; c++, i++){ptr[i] = c;}std::cout << "写入后地址内容是:" << ptr << std::endl;Myfree(ptr, SIZE);return 0;
}

运行效果:
在这里插入图片描述


🌈我的分享也就到此结束啦🌈
要是我的分享也能对你的学习起到帮助,那简直是太酷啦!
若有不足,还请大家多多指正,我们一起学习交流!
📢公主,王子:点赞👍→收藏⭐→关注🔍
感谢大家的观看和支持!祝大家都能得偿所愿,天天开心!!!


http://www.hkcw.cn/article/tVRITNgbBZ.shtml

相关文章

深度学习驱动的超高清图修复技术——综述

Deep Learning-Driven Ultra-High-Definition Image Restoration: A Survey Liyan Wang, Weixiang Zhou, Cong Wang, Kin-Man Lam, Zhixun Su, Jinshan Pan Abstract Ultra-high-definition (UHD) image restoration​​ aims to specifically solve the problem of ​​quali…

【Docker系列】Docker 容器内安装`ps`命令

博客目录 一、为什么需要在 Docker 容器中安装ps命令二、不同 Linux 发行版的安装方法1. Alpine Linux 镜像的安装方法2. Debian/Ubuntu 镜像的安装方法3. CentOS/RHEL 镜像的安装方法 三、验证安装与基本使用四、永久解决方案&#xff1a;修改 Dockerfile1. Alpine 基础镜像的…

【KWDB 创作者计划】_再热垃圾发电汽轮机仿真与监控系统:KaiwuDB 批量插入10万条数据性能优化实践

再热垃圾发电汽轮机仿真与监控系统&#xff1a;KaiwuDB 批量插入10万条数据性能优化实践 我是一台N25-3.82/390型汽轮机&#xff0c;心脏在5500转/分的轰鸣中跳动。垃圾焚烧炉是我的胃&#xff0c;将人类遗弃的残渣转化为金色蒸汽&#xff0c;沿管道涌入我的胸腔。 清晨&#x…

对蚁群算法的理解和实例详解

目录 一、算法概述 二、实例详解 1&#xff09;问题分析 2&#xff09;初始化参数 2&#xff09;设置蚂蚁初始位置 3&#xff09;选择路径 4&#xff09;记录本次最佳路径 5&#xff09;更新信息素 6&#xff09;清空禁忌表 三、计算结果 四、总结 一、算法概述 一群…

【PowerPoint专栏】PowerPoint的保存选项

在PowerPoint的保存选项中有非常多的可用选项,保存的类型也非常多。 在PowerPoint中的工具选项中同样有一些相关的菜单操作帮助用户完成一些特殊操作。 在

直击2025粤港澳大湾区车展 科技引领未来车展

5月31日,第二十九届粤港澳大湾区车展在深圳国际会展中心(宝安)拉开帷幕。本届车展延续“面向科技、面向未来、面向市场”的主题,以“科技Alpha车展”为核心方向,探索汽车前沿科技。展会规模超过26万平方米,有超8万平方米的户外活动体验区及试驾专区。车展期间,全球近百家…

新王加冕!巴黎5比0国米首夺欧冠 年轻风暴席卷欧洲

北京时间6月1日凌晨,2024至2025赛季欧冠联赛决赛在德国慕尼黑安联球场进行。经过90分钟的激战,法甲巴黎圣日耳曼队以5比0大胜意甲国际米兰队,夺得队史首座“大耳朵杯”。此前的淘汰赛中,“大巴黎”先后淘汰了利物浦队、阿斯顿维拉队和阿森纳队三支英超劲旅。而国米则在半决…

定制一款国密浏览器(13):预置国密根证书到浏览器

由于国密算法没有得到国外的认可,所以 Chromium、Firefox 等浏览器均不支持国密算法。即使我们修改了 Chromium 的源码,增加了国密算法的支持,但还不能在浏览器中正常使用。因为这涉及到证书的信任问题,国密证书都是国内厂商签发的,国密根证书并没有集成到系统和浏览器中。…

新闻数据加载(鸿蒙App开发实战)

本案例基于ArkTS的声明式开发范式&#xff0c;介绍了数据请求和onTouch事件的使用。包含以下功能&#xff1a; 数据请求。列表下拉刷新。列表上拉加载。 网络数据请求需要权限&#xff1a;ohos.permission.INTERNET 一、案例效果截图 操作说明&#xff1a; 点击应用进入主页…

Baklib企业CMS全流程管控与智能协作

企业CMS全流程管控方案解析 现代企业内容管理中&#xff0c;全流程管控的实现依赖于对生产、审核、发布及迭代环节的系统化整合。通过动态发布引擎与元数据智能标记技术&#xff0c;系统可自动匹配内容与目标场景&#xff0c;实现标准化模板驱动的快速部署。针对多分支机构的复…

当前用户的Git全局配置情况:git config --global --list

通过config命令可以查询当前用户的全局配置情况。这些配置项定义了 Git 在全局范围内的行为&#xff0c;包括如何处理大文件、SSL 证书验证以及提交时的用户信息。 git config --global --list http.sslVerifyfalse 这个配置项禁用了 SSL 证书验证。这在与自签名证书的 Git 服…

编辑器之神 Vim

终于到了主包最期待的环节了 简单介绍 这是linux中最能装逼的一个环节 服务器哪有界面版的&#xff0c;都是纯粹的命令行 这个时候操作就比较复杂&#xff0c;需要使用一些另类的编辑器 介绍几个编辑器吧 vi nano emacs vim&#xff0c;这些都是命令版的编辑器&#xff0c;基…

任务19:实现山东省气温预测

任务描述 知识点&#xff1a; 时间序列分析 重 点&#xff1a; 指数平滑法ARIMA模型Python连接数据库&#xff0c;查询数据 内 容&#xff1a; 读取并创建时序数据使用指数平滑法建立模型&#xff0c;并预测下一年山东省各月的平均气温使用ARIMA建立模型&#xff0c;并…

C++ - STL #什么是STL #STL的版本 #闭源开源 #STL的六大组件

文章目录 前言 一、什么是STL 二、STL的版本 1、原始版本 2、P.J.版本 3、RW版本 4、SGI版本 三、闭源、开源 四、STL的六大组件 总结 前言 路漫漫其修远兮&#xff0c;吾将上下而求索&#xff1b; 一、什么是STL STL(standard template libaray 标准模板库)&#…

学习STC51单片机22(芯片为STC89C52RCRC)

记住这个AT指令千万不要去脑子记&#xff0c;要用手册查 每日一言 努力不是为了感动谁&#xff0c;而是为了不辜负自己的野心。 硬件&#xff1a;ESP8266 wife模块 蓝牙&#xff0c;ESP-01s&#xff0c;Zigbee&#xff0c;NB-lot等通信模块都是基于AT指令的设计 老样子 我们用…

华为OD机试真题——统计匹配的二元组个数(2025A卷:100分)Java/python/JavaScript/C++/C语言/GO六种最佳实现

2025 A卷 100分 题型 本文涵盖详细的问题分析、解题思路、代码实现、代码详解、测试用例以及综合分析; 并提供Java、python、JavaScript、C++、C语言、GO六种语言的最佳实现方式! 2025华为OD真题目录+全流程解析/备考攻略/经验分享 华为OD机试真题《统计匹配的二元组个数》:…

LLMTIME: 不用微调!如何用大模型玩转时间序列预测?

今天是端午节&#xff0c;端午安康&#xff01;值此传统佳节之际&#xff0c;我想和大家分享一篇关于基于大语言模型的时序预测算法——LLMTIME。随着人工智能技术的飞速发展&#xff0c;利用大型预训练语言模型&#xff08;LLM&#xff09;进行时间序列预测成为一个新兴且极具…

Unity3D仿星露谷物语开发56之保存角色位置到文件

1、目标 游戏中通过Save Game保存角色位置&#xff0c;当重启游戏后&#xff0c;通过Load Game可以恢复角色的位置。 2、Player对象操作 &#xff08;1&#xff09;组件添加 给Hierarchy下的Player组件添加Generate GUID组件。 &#xff08;2&#xff09;修改SceneSave.cs脚…

AI书签管理工具开发全记录(八):Ai创建书签功能实现

文章目录 AI书签管理工具开发全记录&#xff08;八&#xff09;&#xff1a;AI智能创建书签功能深度解析前言 &#x1f4dd;1. AI功能设计思路 &#x1f9e0;1.1 传统书签创建的痛点1.2 AI解决方案设计 2. 后端API实现 ⚙️2.1 新增url相关工具方法2.1 创建后端api2.2 创建crea…

【计算机网络】第3章:传输层—概述、多路复用与解复用、UDP

目录 一、概述和传输层服务 二、多路复用与解复用 三、无连接传输&#xff1a;UDP 四、总结 &#xff08;一&#xff09;多路复用与解复用 &#xff08;二&#xff09;UDP 一、概述和传输层服务 二、多路复用与解复用 三、无连接传输&#xff1a;UDP 四、总结 &#xff08…