当前位置: 首页 > 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 …...

Qt修仙之路2-1 仿QQ登入 法宝初成

widget.cpp #include "widget.h" #include<QDebug> //实现槽函数 void Widget::login1() {QString userusername_input->text();QString passpassword_input->text();//如果不勾选无法登入if(!check->isChecked()){qDebug()<<"xxx"&…...

DeepSeek-V3 论文解读:大语言模型领域的创新先锋与性能强者

论文链接&#xff1a;DeepSeek-V3 Technical Report 目录 一、引言二、模型架构&#xff1a;创新驱动性能提升&#xff08;一&#xff09;基本架构&#xff08;Basic Architecture&#xff09;&#xff08;二&#xff09;多令牌预测&#xff08;Multi-Token Prediction&#xf…...

配置#include “nlohmann/json.hpp“,用于处理json文件

#include “nlohmann/json.hpp” // 需要安装 nlohmann/json.hpp 头文件 using json = nlohmann::json; 下载链接:https://github.com/nlohmann/json/tree/develop 1.下载并解压:首先,需要从nlohmann/json的GitHub仓库下载源代码,并解压得到的文件。 地址: nlohmann/json…...

索引失效的14种常见场景

在 MySQL 中&#xff0c;索引有时可能会失效&#xff0c;导致查询性能下降。以下是常见的 14 种场景&#xff0c;在这些场景下&#xff0c;索引可能会失效 1. 使用 OR 连接多个条件 场景: 当查询中包含 OR 时&#xff0c;如果 OR 连接的多个条件中有一个没有使用索引&#xff0…...

解决com.kingbase8.util.KSQLException: This _connection has been closed.

问题描述 一个消息管理系统,系统采用kingbase8数据库,数据库采用单体模式,后台应用也采用springboot单体模式。系统正式上线后,出现几个JDBC响应的异常信息: com.kingbase8.util.KSQLException: An I/O error occurred while sending to the backend.java.net.SocketTime…...

openAI官方prompt技巧(二)

1. 赋予 ChatGPT 角色 为 ChatGPT 指定一个角色&#xff0c;让其从特定的身份或视角回答问题。这有助于生成针对特定受众或场景的定制化回答。 例如&#xff1a; 你是一名数据分析师&#xff0c;负责我们的市场营销团队。请总结上个季度的营销活动表现&#xff0c;并强调与未…...

【非 root 用户下全局使用静态编译的 FFmpeg】

在非 root 用户下全局使用静态编译的 FFmpeg&#xff0c;可以按照以下方法操作&#xff1a; 1. 下载静态编译的 FFmpeg 如果你还没有下载静态编译的 FFmpeg&#xff0c;可以从官方网站获取&#xff1a; wget https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd6…...

【嵌入式 Linux 音视频+ AI 实战项目】瑞芯微 Rockchip 系列 RK3588-基于深度学习的人脸门禁+ IPC 智能安防监控系统

前言 本文主要介绍我最近开发的一个个人实战项目&#xff0c;“基于深度学习的人脸门禁 IPC 智能安防监控系统”&#xff0c;全程满帧流畅运行。这个项目我目前全网搜了一圈&#xff0c;还没发现有相关类型的开源项目。这个项目只要稍微改进下&#xff0c;就可以变成市面上目前…...

前端布局与交互实现技巧

前端布局与交互实现技巧 1. 保持盒子在中间位置 在网页设计中&#xff0c;经常需要将某个元素居中显示。以下是一种常见的实现方式&#xff1a; HTML 结构 <!doctype html> <html lang"en"> <head><meta charset"UTF-8"><m…...

idea 找不到或者无法加载主类

idea项目&#xff0c;之前一直是正常运行的&#xff0c;放假了之后再回来就遇到启动不了的问题。 WebApplication这个类右键运行的时候&#xff0c;也提示找不到主类。 对于这种之前运行没有问题&#xff0c;突然出问题的项目。 我的点是没有改动代码和数据的情况下项目就跑不起…...