当前位置: 首页 > news >正文

mmap 文件映射

🌈 个人主页:Zfox_
🔥 系列专栏:Linux

目录

  • 一:🔥 mmap介绍
    • 🦋 基本说明
    • 🦋 参数介绍
    • 🦋 返回值
  • 二:🔥 demo代码
    • 🦋 写入映射
    • 🦋 读取映射
  • 三:🔥 极简模拟实现 malloc
  • 四:🔥 共勉

一:🔥 mmap介绍

NAMEmmap, munmap - map or unmap files or devices into memorySYNOPSIS#include <sys/mman.h>void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);int munmap(void *addr, size_t length);

🦋 基本说明

  • 🧑‍💻 允许用户空间程序将文件或设备的内容直接映射到进程的虚拟地址空间中。通过 mmap ,程序可以高效地访问文件数据,而无需通过传统的 read 或 write 系统调用进行数据的复制
  • 🧑‍💻 mmap 还可以用于实现共享内存,允许不同进程间共享数据
    在这里插入图片描述

🦋 参数介绍

💻

  • 🌾 🦁 void *addr 一个提示地址,表示希望映射区域开始的地址。然而,这个地址可能会被内核忽略,特别是当我们没有足够的权限来请求特定的地址时。如果 addr 是 NULL,则系统会自动选择一个合适的地址。
  • size_t length要映射到进程地址空间中的字节数。这个长度必须是系统页面大小的整数倍(通常是 4KB,但可能因系统而异)。如果指定的 length 不是页面大小的整数倍,系统可能会向上舍入到最近的页面大小边界(系统内存页大小为 4KB(即 4096 字节),而请求的内存大小为 3500 字节,则按照向上舍入的原则,应分配 4096 字节的内存)。
  • int prot指定了映射区域的内存保护属性。可以是以下值的组合(使用按位或运算符 |):
    • PROT_READ映射区域可读。
    • PROT_WRITE映射区域可写。
    • PROT_EXEC映射区域可执行。
  • int flags指定了映射的类型和其他选项:
    • MAP_PRIVATE创建一个私有映射。对映射区域的修改不会反映到底层文件中。
    • MAP_SHARED创建一个共享映射。对映射区域的修改会反映到底层文件中(前提是文件是以写方式打开的,并且文件系统支持这种操作)。
    • 其他选项(如 MAP_ANONYMOUS、MAP_ANONYMOUS_SHARED 等)可能也存在于某些系统上,用于创建不与文件关联的匿名映射。
The flags argumentThe flags argument determines whether updates to the mapping are visible to other processes mapping the same region, and whether updates are carried through to the underlying file.  This behavior is determined by including exactly one of the following values in flags:MAP_SHAREDShare this mapping.  Updates to the mapping are visible to other processes mapping the same region, and (in the case of file-backed mappings) are carried through to the underlying  file.(To precisely control when updates are carried through to the underlying file requires the use of msync(2).)MAP_SHARED_VALIDATE (since Linux 4.15)This  flag  provides  the  same behavior as MAP_SHARED except that MAP_SHARED mappings ignore unknown flags in flags.  By contrast, when creating a mapping using MAP_SHARED_VALIDATE, thekernel verifies all passed flags are known and fails the mapping with the error EOPNOTSUPP for unknown flags.  This mapping type is also required to be able to  use  some  mapping  flags(e.g., MAP_SYNC).MAP_PRIVATECreate  a  private copy-on-write mapping.  Updates to the mapping are not visible to other processes mapping the same file, and are not carried through to the underlying file.  It is un‐specified whether changes made to the file after the mmap() call are visible in the mapped region.
  • int fd : 一个有效的文件描述符,指向要映射的文件或设备。对于匿名映射,这个参数可以是 -1 (在某些系统上,也可以使用 MAP_ANONYMOUS 或 MAP_ANON 标志来指定匿名映射,此时 fd 参数会被忽略)
  • off_t offset : 文件中的起始偏移量,即映射区域的开始位置。offset 和 length 一起定义了映射区域在文件中的位置和大小。

🦋 返回值

RETURN VALUEOn success, mmap() returns a pointer to the mapped area.  On error, the value MAP_FAILED (that is, (void *) -1) is returned, and errno is set to indicate the cause of the error.On success, munmap() returns 0.  On failure, it returns -1, and errno is set to indicate the cause of the error (probably to EINVAL).

二:🔥 demo代码

🧑‍💻 引入一个手动调整文件大小的系统调用
在这里插入图片描述

🦋 写入映射

#include <iostream>
#include <string>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>#define PAGE_SIZE 4096// write_map filename
int main(int argc, char *argv[])
{if(argc != 2){std::cout << "Usage: " << argv[0] << " filename" << std::endl;return 1;}// 1. 打开目标文件,mmap 需要你自己先打开文件int fd = ::open(argv[1], O_RDWR | O_CREAT | O_TRUNC, 0666);if(fd < 0){std::cout << "Failed to open file: " << argv[1] << std::endl;return 2;}// 2. 我们要手动调整一下文件的大小,方便进行合法映射,用0填充if(ftruncate(fd, PAGE_SIZE) == -1){std::cout << "Failed to ftruncate file: " << argv[1] << std::endl;return 3;}// 3. 文件映射char *shmaddr = (char*)::mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);if(shmaddr == MAP_FAILED){std::cout << "Failed to mmap file: " << argv[1] << std::endl;return 4;}// 4. 进行文件操作for(char c = 'a'; c <= 'z'; c++){shmaddr[c - 'a'] = c;sleep(1);}// 5. 关闭映射if(::munmap(shmaddr, PAGE_SIZE) == -1){std::cout << "Failed to munmap file: " << argv[1] << std::endl;return 5;}::close(fd);return 0;
}

💻 运行:

root@# ./a.out log.txt
^C
root@# ll
total 44
drwxr-xr-x 2 root root  4096 Feb  8 23:35 ./
drwxr-xr-x 7 root root  4096 Feb  8 20:58 ../
-rwxr-xr-x 1 root root 16832 Feb  8 23:35 a.out*
-rw-r--r-- 1 root root  4096 Feb  8 23:35 log.txt
-rw-r--r-- 1 root root  1409 Feb  8 21:38 WriteMmap.cc

🧑‍💻 这里我们可以看到 log.txt 文件的大小正是 4096,剩余的用 null 填充,文件内容也是我们写入的 a - z
在这里插入图片描述

🦋 读取映射

#include <iostream>
#include <string>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>// write_map filename
int main(int argc, char *argv[])
{if(argc != 2){std::cout << "Usage: " << argv[0] << " filename" << std::endl;return 1;}// 1. 打开目标文件,mmap 需要你自己先打开文件int fd = ::open(argv[1], O_RDONLY);if(fd < 0){std::cout << "Failed to open file: " << argv[1] << std::endl;return 2;}// 2. 获取文件大小struct stat st;::fstat(fd, &st);// 3. 文件映射char *shmaddr = (char*)::mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);if(shmaddr == MAP_FAILED){std::cout << "Failed to mmap file: " << argv[1] << std::endl;return 4;}// 4. 进行文件操作std::cout << "File content: " << shmaddr << std::endl;// 5. 关闭映射if(::munmap(shmaddr, st.st_size) == -1){std::cout << "Failed to munmap file: " << argv[1] << std::endl;return 5;}::close(fd);return 0;
}

💻 运行:
此时我们读取刚才写入文件的内容 a-z:

root@# ./a.out log.txt
File content: abcdefghijklmnopqrstuvwxyz

三:🔥 极简模拟实现 malloc

🧑‍💻 在内存映射中,MAP_PRIVATE 和 MAP_SHARED 是两种不同的映射类型,它们定义了对映射区域的修改是如何反映到底层文件的。

  • MAP_PRIVATE(私有映射)

    • ⚠️ 当使用 MAP_PRIVATE 标志创建映射时,会生成一个写时拷贝(copy-on-write,COW)的私有映射,这些修改实际上是在内存中进行的,并且是私有的,不会影响其他进程的映射或文件在磁盘上的实际内容。
    • ⚠️ 对这个映射区域的任何修改都不会影响底层文件,也不会影响其他进程的映射。
  • MAP_SHARED(共享映射)

    • ⚠️ 使用 MAP_SHARED 标志创建的映射是可写的,并且对映射区域的修改会反映到底层文件中。
    • ⚠️ 这种映射类型允许多个进程共享对同一文件的访问,并且所有进程看到的是文件的最新状态。
    • ⚠️ 如果一个进程修改了映射区域,其他进程也会看到这些更改。
    • ⚠️ 共享映射适用于多个进程需要协作修改文件内容的情况。
  • MAP_ANONYMOUS (匿名映射)

    • 是 mmap 系统调用中的一个标志,用于创建匿名映射。匿名映射区是指创建的映射区域不与任何文件关联,而是由操作系统分配的匿名内存。在调用 mmap 进行匿名映射的时候,是将进程虚拟内存空间中的某一段虚拟内存区域与物理内存中的匿名内存页进行映射。
#include <iostream>
#include <string>
#include <cstring>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>void *my_malloc(size_t size)
{if (size > 0){void *ptr = ::mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);if (ptr == MAP_FAILED){return nullptr;}return ptr;}return nullptr;
}void my_free(void *start, size_t size)
{if (start != nullptr && size > 0){int ret = ::munmap(start, size);if (ret != 0){perror("munmap");}}
}int main()
{char *ptr = (char*)my_malloc(1024);if (ptr == nullptr){std::cerr << "malloc failed" << std::endl;return 1;}// 使用分配的内存 (这里只是简单地打印指针值)printf("Allocated memory at address: %p\n", ptr);//...在这里可以使用ptr指向的内存...memset(ptr, 'A', 1024);for (int i = 0; i < 1024; i++){printf("%c ", ptr[i]);fflush(stdout);sleep(1);}my_free(ptr, 1024);return 0;
}

💻 运行:

root@# ./a.out 
Allocated memory at address: 0x7f1810db7000
A A A A A A A A A A A

👀 为了更好的观察我们所创建的内存空间 我们使用 gdb 调试工具

root@# g++ MallocMmap.cc -g -std=c++11
root@# gdb ./a.out 

在这里插入图片描述

我们在第36行打一个断点,然后运行程序

在这里插入图片描述

可以看到此时 ptr 的地址是 0

在这里插入图片描述

此时我们输入:

(gdb) info proc mapping 
  • 在 GDB(GNU调试器)中,info proc mapping 命令用于显示当前进程的内存映射信息,包括可执行文件的代码段、数据段、堆和栈等信息,以及共享库的地址空间等信息。通过这些信息,我们可以更好地了解程序的内存使用情况,方便我们进行调试和优化。

  • 具体来说,该命令会列出每个内存区域的起始地址、结束地址、大小、偏移量和访问权限等详细信息。
    在这里插入图片描述

  • 可以看到 ptr 对应的地址是进行了内存映射的(匿名映射)MAP_ANONYMOUS

📚 我们知道实际上虚拟地址空间都会有一个 struct vm_area_struct 然后链入自己的 pcb(task_struct)

在这里插入图片描述

当前我们做文件映射就会有文件描述符,而文件描述符是作为当前进程文件描述符表的索引去找对应的文件的,但是真正在 linux 内核里找到一个文件用的是 struct_file 结构体

那么进程地址空间是如何跟文件关联起来的呢?

在这里插入图片描述

🎯 我们发现在 linux 内核源代码 struct vm_area_struct 中包含了一个 struct_file * vm_file 直接指向打开的文件,文件都找到了,文件里又有什么内容找不到呢

四:🔥 共勉

😋 以上就是我对 mmap 文件映射 的理解, 觉得这篇博客对你有帮助的,可以点赞收藏关注支持一波~ 😉
在这里插入图片描述

相关文章:

mmap 文件映射

&#x1f308; 个人主页&#xff1a;Zfox_ &#x1f525; 系列专栏&#xff1a;Linux 目录 一&#xff1a;&#x1f525; mmap介绍&#x1f98b; 基本说明&#x1f98b; 参数介绍&#x1f98b; 返回值 二&#xff1a;&#x1f525; demo代码&#x1f98b; 写入映射&#x1f98b…...

基于微信小程序的医院预约挂号系统的设计与实现

hello hello~ &#xff0c;这里是 code袁~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f981;作者简介&#xff1a;一名喜欢分享和记录学习的在校大学生…...

【Linux】Socket编程—UDP

&#x1f525; 个人主页&#xff1a;大耳朵土土垚 &#x1f525; 所属专栏&#xff1a;Linux系统编程 这里将会不定期更新有关Linux的内容&#xff0c;欢迎大家点赞&#xff0c;收藏&#xff0c;评论&#x1f973;&#x1f973;&#x1f389;&#x1f389;&#x1f389; 文章目…...

2025年物联网相关专业毕业论文选题参考,文末联系,选题相关资料提供

一、智能穿戴解决方案研究方向 序号解决方案论文选题论文研究方向1智能腰带健康监测基于SpringBoot和Vue的智能腰带健康监测数据可视化平台开发研究如何利用SpringBoot和Vue技术栈开发一个数据可视化平台&#xff0c;用于展示智能腰带健康监测采集的数据&#xff0c;如心率、血…...

如何在WPS和Word/Excel中直接使用DeepSeek功能

以下是将DeepSeek功能集成到WPS中的详细步骤&#xff0c;无需本地部署模型&#xff0c;直接通过官网连接使用&#xff1a;1. 下载并安装OfficeAI插件 &#xff08;1&#xff09;访问OfficeAI插件下载地址&#xff1a;OfficeAI助手 - 免费办公智能AI助手, AI写作&#xff0c;下载…...

DeepSeek之Api的使用(将DeepSeek的api集成到程序中)

一、DeepSeek API 的收费模式 前言&#xff1a;使用DeepSeek的api是收费的 免费版&#xff1a; 可能提供有限的免费额度&#xff08;如每月一定次数的 API 调用&#xff09;&#xff0c;适合个人开发者或小规模项目。 付费版&#xff1a; 超出免费额度后&#xff0c;可能需要按…...

使用DeepSeek实现AI自动编码

最近deepseek很火&#xff0c;低成本训练大模型把OpenAI、英伟达等股票搞得一塌糊涂。那它是什么呢&#xff0c;对于咱们程序员编码能有什么用呢&#xff1f;DeepSeek 是一款先进的人工智能语言模型&#xff0c;在自然语言处理和代码生成方面表现出色。它经过大量代码数据训练&…...

30~32.ppt

目录 30.导游小姚-介绍首都北京❗ 题目​ 解析 31.小张-旅游产品推广文章 题目 解析 32.小李-水的知识❗ 题目​ 解析 30.导游小姚-介绍首都北京❗ 题目 解析 新建幻灯片-从大纲-重置-检查设计→主题对话框→浏览主题&#xff1a;考生文件夹&#xff08;注意&#x…...

Java的匿名内部类转为lamada表达式

在Java中&#xff0c;匿名内部类通常用于创建没有命名类的实例。例如&#xff0c;你可能需要创建一个实现了某个接口的匿名类&#xff0c;或者在需要重写某个方法时使用它。在Java 8及更高版本中&#xff0c;你可以使用Lambda表达式来替代传统的匿名内部类&#xff0c;使得代码…...

redis高级数据结构Stream

文章目录 背景stream概述消息 ID消息内容常见操作独立消费创建消费组消费 Stream弊端Stream 消息太多怎么办?消息如果忘记 ACK 会怎样?PEL 如何避免消息丢失?分区 Partition Stream 的高可用总结 背景 为了解决list作为消息队列是无法支持消息多播问题&#xff0c;Redis5.0…...

LeetCode781 森林中的兔子

问题描述 在一片神秘的森林里&#xff0c;住着许多兔子&#xff0c;但是我们并不知道兔子的具体数量。现在&#xff0c;我们对其中若干只兔子进行提问&#xff0c;问题是 “还有多少只兔子与你&#xff08;指被提问的兔子&#xff09;颜色相同&#xff1f;” 我们将每只兔子的…...

单硬盘槽笔记本更换硬盘

背景 本人的笔记本电脑只有一个硬盘槽&#xff0c;而且没有M.2的硬盘盒&#xff0c;只有一个移动硬盘 旧硬盘&#xff1a;512G 新硬盘&#xff1a;1T 移动硬盘&#xff1a;512G 参考链接&#xff1a;https://www.bilibili.com/video/BV1iP41187SW/?spm_id_from333.1007.t…...

EB生成配置的过程

EB Tresos Studio,简称EB,通过图形化的模式进行配置生成,并根据选项配置生成配置代码,即 MCAL 层各个模块的配置参数。 在 MCAL 代码中,分为静态代码和配置代码。静态代码,就是 AUTOSAR 规范内容,包含对硬件的封装以及标准化接口的封装;配置代码一般用于配置初始化结构…...

量化交易数据获取:xtquant库的高效应用

量化交易数据获取&#xff1a;xtquant库的高效应用 在量化交易领域&#xff0c;历史行情数据的重要性不言而喻。它不仅为策略回测提供基础&#xff0c;也是实时交易决策的重要参考。本文将介绍如何使用xtquant库来高效获取和处理历史行情数据。 技术背景与应用场景 对于量化…...

哨兵模式与 Redis Cluster:高可用 Redis 的深度剖析

深入探讨 Redis 高可用性解决方案&#xff1a;哨兵模式与 Redis Cluster 一、哨兵模式&#xff08;Redis Sentinel&#xff09;深入解析 &#xff08;一&#xff09;工作原理详解 哨兵模式通过一个或多个哨兵实例监控 Redis 主从复制集群&#xff0c;确保在主节点发生故障时…...

C++20新特性

作者&#xff1a;billy 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 前言 C20 是 C 标准中的一个重要版本&#xff0c;引入了许多新特性和改进&#xff0c;包括模块&#xff08;Modules&#xff09;、协程…...

电机实验曲线数据提取

处理Python 代码供参考: 1、曲线数据还原 import cv2 import numpy as np import matplotlib.pyplot as plt# 读取图像 image_path 1.png image cv2.imread(image_path) image_copy image.copy() # 创建图像副本&#xff0c;用于叠加显示# 转换为灰度图像 gray cv2.cvtCo…...

windows蓝牙驱动开发-调试及支持的HCI和事件

调试蓝牙配置文件驱动程序 开发蓝牙配置文件驱动程序时&#xff0c;可以使用驱动程序验证程序来协助其调试。 若要启用验证检查&#xff0c;必须为 Bthusb.sys 启用驱动程序验证程序。 如果不执行此操作&#xff0c;将禁用验证检查。 若要完全利用验证检查&#xff0c;请确保…...

Excel大数据量导入导出

github源码 地址&#xff08;更详细&#xff09; : https://github.com/alibaba/easyexcel 文档&#xff1a;读Excel&#xff08;文档已经迁移&#xff09; B 站视频 : https://www.bilibili.com/video/BV1Ff4y1U7Qc 一、JAVA解析EXCEL工具EasyExcel Java解析、生成Excel比较…...

Linux系统命令无法使用(glib库相关问题)

1.背景描述 Yum强制安装了一些软件&#xff0c;安装软件成功无报错&#xff0c;完成后不久突然发现系统出问题了&#xff0c;所有的命令无法使用了&#xff0c;如ls、mv、cat等基本命令报错。 relocation error&#xff1a; /lib64/libpthread.so.0: symbol_libc_dl_error_tsd …...

idea大量爆红问题解决

问题描述 在学习和工作中&#xff0c;idea是程序员不可缺少的一个工具&#xff0c;但是突然在有些时候就会出现大量爆红的问题&#xff0c;发现无法跳转&#xff0c;无论是关机重启或者是替换root都无法解决 就是如上所展示的问题&#xff0c;但是程序依然可以启动。 问题解决…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地

借阿里云中企出海大会的东风&#xff0c;以**「云启出海&#xff0c;智联未来&#xff5c;打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办&#xff0c;现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂

蛋白质结合剂&#xff08;如抗体、抑制肽&#xff09;在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上&#xff0c;高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术&#xff0c;但这类方法普遍面临资源消耗巨大、研发周期冗长…...

前端导出带有合并单元格的列表

// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...

ffmpeg(四):滤镜命令

FFmpeg 的滤镜命令是用于音视频处理中的强大工具&#xff0c;可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下&#xff1a; ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜&#xff1a; ffmpeg…...

Spring是如何解决Bean的循环依赖:三级缓存机制

1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间‌互相持有对方引用‌,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...

Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)

Aspose.PDF 限制绕过方案&#xff1a;Java 字节码技术实战分享&#xff08;仅供学习&#xff09; 一、Aspose.PDF 简介二、说明&#xff08;⚠️仅供学习与研究使用&#xff09;三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP

编辑-虚拟网络编辑器-更改设置 选择桥接模式&#xff0c;然后找到相应的网卡&#xff08;可以查看自己本机的网络连接&#xff09; windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置&#xff0c;选择刚才配置的桥接模式 静态ip设置&#xff1a; 我用的ubuntu24桌…...

LabVIEW双光子成像系统技术

双光子成像技术的核心特性 双光子成像通过双低能量光子协同激发机制&#xff0c;展现出显著的技术优势&#xff1a; 深层组织穿透能力&#xff1a;适用于活体组织深度成像 高分辨率观测性能&#xff1a;满足微观结构的精细研究需求 低光毒性特点&#xff1a;减少对样本的损伤…...

(一)单例模式

一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...