mmap核心原理和用途及其与内存映射段的关系

mmap 是 Linux/Unix 系统中的一个关键系统调用,全称是 Memory Map(内存映射)。它的核心功能是将 文件、设备或匿名内存 直接映射到进程的虚拟地址空间,从而实现高效的内存访问和操作。以下是其核心原理和用途的详细说明:


1. 核心功能

  • 内存映射文件:将文件内容映射到进程的虚拟内存中,直接通过指针读写文件,无需传统的 read/write 系统调用。
  • 匿名内存映射:分配不关联任何文件的纯内存块(类似 malloc,但更灵活)。
  • 共享内存:多个进程可映射同一块内存,实现高效进程间通信(IPC)。

2. 工作原理

  • 系统调用原型

    void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
    
  • 参数说明

    • addr:建议的映射起始地址(通常设为 NULL,由内核自动选择)。
    • length:映射区域的长度(需按页对齐,如 4KB)。
    • prot:内存保护权限(如 PROT_READ | PROT_WRITE)。
    • flags:映射类型(MAP_SHARED 共享内存,MAP_PRIVATE 私有副本,MAP_ANONYMOUS 匿名内存等)。
    • fd:文件描述符(匿名映射时设为 -1)。
    • offset:文件映射的起始偏移量(通常为 0)。
  • 返回值:成功返回映射区域的起始地址,失败返回 MAP_FAILED


3. 主要用途

(1) 高效文件 I/O

  • 直接读写内存:映射文件后,操作内存即操作文件,避免频繁的 read/write 系统调用。
  • 惰性加载:文件内容按需加载到内存(缺页中断机制),适合处理大文件。
  • 示例
    int fd = open("data.txt", O_RDWR);
    char *ptr = mmap(NULL, file_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    ptr[0] = 'A'; // 直接修改文件内容
    munmap(ptr, file_size); // 解除映射
    

(2) 动态内存分配

  • 替代 mallocmalloc 在分配大块内存时可能使用 mmap(通过 MAP_ANONYMOUS 标志)。
  • 匿名内存映射
    void *mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    

(3) 进程间共享内存(IPC)

  • 共享内存通信:多个进程映射同一文件或匿名内存,共享数据。
  • 示例
    // 进程 A
    void *shm = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    sprintf(shm, "Hello from Process A");// 进程 B(映射同一文件)
    printf("%s\n", (char*)shm); // 输出 "Hello from Process A"
    

(4) 实现零拷贝(Zero-Copy)

  • 避免数据复制:网络传输或文件操作时,直接映射内存到用户空间,减少内核与用户空间的数据拷贝。

4. 与 malloc/brk 的对比

特性mmapmalloc/brk
内存来源文件、匿名内存、共享内存堆内存(通过 brksbrk
分配粒度按页(如 4KB)按字节(实际可能按块管理)
碎片问题较少(大块独立映射)较多(频繁分配释放导致碎片)
适用场景大内存分配、文件映射、IPC常规小内存分配
性能开销初始映射开销大,后续访问快分配速度快,但碎片可能影响性能

5. 优缺点

  • 优点
    • 高效文件操作:减少系统调用和数据拷贝。
    • 共享内存:跨进程通信速度快。
    • 灵活内存管理:支持动态调整映射区域(mremap)。
  • 缺点
    • 内存对齐要求:映射长度需按页对齐。
    • 资源泄漏风险:需手动调用 munmap 释放。
    • 文件同步问题:修改后需调用 msync 确保数据写入磁盘。

6. 关键注意事项

  • 错误处理:检查返回值是否为 MAP_FAILED,并用 perror 诊断错误。
  • 释放内存:使用 munmap 释放映射区域,不可用 free
  • 同步数据:修改文件映射后,调用 msync 确保数据持久化。
  • 线程安全:多线程中操作同一映射区域需加锁。

7. 示例代码(匿名内存分配)

#include <sys/mman.h>int main() {size_t size = 4096; // 1 页大小// 分配匿名内存(可读可写)void *mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);if (mem == MAP_FAILED) {perror("mmap failed");return 1;}// 使用内存memset(mem, 0, size);// 释放munmap(mem, size);return 0;
}

8.mmap与内存映射段

mmap内存映射段(Memory-Mapped Segment)是操作系统内存管理中的两个紧密相关的概念。mmap 是用户态操作内存映射段的接口,而内存映射段是进程虚拟地址空间中用于存储映射内容(如文件、共享内存等)的区域。以下是二者的关系及详细说明:

(1) 内存映射段是什么?

在进程的虚拟地址空间中,内存映射段(也称为 内存映射区域)是专门用于存放通过 mmap 系统调用映射的内容的区域。其典型位置如下(以 Linux 进程地址空间为例):

高地址
┌───────────────────────┐
│ 栈(Stack) │
├───────────────────────┤
│ … │
├───────────────────────┤
│ 堆(Heap) │ ← 通过 brk/sbrkmalloc 分配
├───────────────────────┤
│ 内存映射段(Memory-Mapped Region)│ ← 通过 mmap 映射的内容
├───────────────────────┤
│ 未初始化数据段(BSS) │
├───────────────────────┤
│ 已初始化数据段(Data) │
├───────────────────────┤
│ 代码段(Text) │
└───────────────────────┘
低地址

内存映射段的特点:

  • 动态扩展:大小由 mmap 的映射操作决定,可动态增长或收缩。
  • 多种用途:可包含文件映射、共享内存、匿名内存等。
  • 分页管理:按页(如 4KB)对齐,由内核通过缺页中断(Page Fault)按需加载数据。

(2) mmap 如何操作内存映射段?

mmap 是用户程序与内存映射段交互的核心接口,具体行为如下:

① 映射文件到内存映射段
  • 通过 mmap 将文件内容映射到内存映射段,进程通过指针直接读写文件,无需 read/write
  • 示例
    int fd = open("data.txt", O_RDWR);
    char *ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    // ptr 指向内存映射段中的文件内容
    ptr[0] = 'X'; // 直接修改文件
    munmap(ptr, 4096); // 解除映射
    
② 分配匿名内存
  • 使用 MAP_ANONYMOUS 标志创建不关联文件的纯内存块,常用于替代 malloc 分配大内存。
  • 示例
    void *mem = mmap(NULL, 1024*1024, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    // mem 指向内存映射段中的匿名内存
    
③ 共享内存(IPC)
  • 多个进程通过 mmap 映射同一文件或匿名内存,实现高效数据共享。
  • 示例
    // 进程 A
    void *shm = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    sprintf(shm, "Hello");// 进程 B(映射同一文件)
    printf("%s\n", (char*)shm); // 输出 "Hello"
    

(3) 内存映射段的管理机制

① 分页与缺页中断
  • 内存映射段的内容按页(如 4KB)管理。
  • 初次访问映射区域时触发 缺页中断,内核将文件内容或物理内存加载到页表中。
② 写时复制(Copy-on-Write)
  • 若使用 MAP_PRIVATE 标志,修改内存映射段时会触发写时复制,生成进程私有的副本。
③ 同步与持久化
  • 修改文件映射后,需调用 msync 强制将内存中的数据写回磁盘。
  • 匿名映射的内容随进程结束自动释放。

(4) mmap 与内存映射段的关系总结

特性mmap 系统调用内存映射段
角色操作接口(用户态函数)存储区域(进程地址空间的一部分)
功能创建、删除、调整内存映射存放文件、共享内存、匿名内存等内容
生命周期显式调用 mmapmunmap 控制由内核管理,随进程终止或 munmap 释放
性能优化减少数据拷贝、支持零拷贝按需加载(惰性分配)、分页管理

(5) 常见问题

mmap 分配的匿名内存与堆内存(malloc)有何区别?
  • 匿名内存:位于内存映射段,按页分配,适合大块内存,释放直接通过 munmap
  • 堆内存:通过 brk/sbrkmalloc 分配,位于堆段,适合小块内存,可能产生碎片。
② 内存映射段会占用物理内存吗?
  • 不会立即占用。内核通过缺页中断按需分配物理内存(惰性加载)。
③ 内存映射段的大小限制?
  • 受进程虚拟地址空间限制(如 32 位系统最大 4GB,64 位系统理论极大)。

(6) 总结

  • mmap 是操作内存映射段的工具,内存映射段是 mmap 映射内容的存储区域。
  • 文件映射、共享内存、匿名内存分配等均通过 mmap 在内存映射段中实现。
  • 理解二者的关系,有助于优化文件 I/O、内存分配和进程间通信的设计。

通过 mmap,开发者可以直接操控内存与文件、设备或共享内存的关系,这在处理高性能 I/O、内存数据库、跨进程通信等场景中非常有用。理解其原理和适用场景,能显著优化程序的效率和资源管理能力。

创作不易,希望大家多多支持,有什么想法欢迎讨论🌹🌹

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

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

相关文章

数据库概论速成期中版

文章目录 引论数据库用户Casual usersNaive usersApplication programmersDatabase administrators 关系模型CAP数据库两种描述关系数据库的方式简单总结 第一范式规则第二范式规则举个例子符合第二规则的操作不符合第二规则的操作 第三范式规则key,superkey,null values,主键&…

解决调用Claude 3.7接口 403 Request not allowed问题

1. 遇到问题 Python 基于 Langchain 对接 Claude 3.7 大模型接口进行问答时&#xff0c;由于国内不在Claude支持的国家和地区&#xff0c;所以一直调不通&#xff0c;错误 anthropic.PermissionDeniedError: Error code: 403 - {error: {type: forbidden, message: Request…

Vue2+Vue3学习笔记

Vue基础介绍 下载并安装vue.js v2 https://v2.cn.vuejs.org/https://v2.cn.vuejs.org/ v3 https://v3.cn.vuejs.org/ 会重定向到Vue.js - 渐进式 JavaScript 框架 | Vue.jsVue.js - 渐进式的 JavaScript 框架https://cn.vuejs.org/ 从v2过渡到v3 在F盘创建v2v3学习笔记 并…

2025年KBS新算法 SCI1区TOP:长颖燕麦优化算法AOO,深度解析+性能实测

目录 1.摘要2.算法原理3.结果展示4.参考文献5.文章&代码获取 1.摘要 本文提出了一种新颖的元启发式算法——长颖燕麦优化算法&#xff08;AOO&#xff09;&#xff0c;该算法灵感来自动画燕麦在环境中的自然行为。AOO模拟了长颖燕麦的三种独特行为&#xff1a;(i) 通过自然…

CentosLinux系统crontab发现执行删除命令失效解决方法

权限或安全策略限制 ​​可能场景​​&#xff1a; ​​### ​​目录权限冲突​​&#xff1a; 你的目录权限为 drwxr-xr-x&#xff08;属主 mssql&#xff09;&#xff0c;但 cron 任务以 root 执行。 ​​风险点​​&#xff1a;若目录内文件属主为 mssql 且权限为 700&…

后验概率最大化(MAP)估计算法原理以及相具体的应用实例附C++代码示例

1. MAP估计基本原理 MAP&#xff08;Maximum A Posteriori&#xff0c;最大后验概率估计&#xff09;是贝叶斯推断中的重要概念&#xff0c;它的目标是&#xff1a; 给定观测数据&#xff0c;找到使得后验概率最大的参数值。 公式化表示&#xff1a; [ θ MAP arg ⁡ max ⁡…

16、路由守卫:设置魔法结界——React 19 React Router

一、魔法结界的本质 "路由守卫是霍格沃茨城堡的隐身斗篷&#xff0c;在时空裂隙中精准控制维度跃迁&#xff01;" 魔法部交通司官员挥舞魔杖&#xff0c;React Router 的嵌套路由在空中交织成星轨矩阵。 ——基于《国际魔法联合会》第7号时空协议&#xff0c;路由守…

从车道检测项目入门open cv

从车道检测项目入门open cv 前提声明&#xff1a;非常感谢b站up主 嘉然今天吃带变&#xff0c;感谢其视频的帮助。同时希望各位大佬积积极提出宝贵的意见。&#x1f60a;&#x1f60a;&#x1f60a;(❁◡❁)(●’◡’●)╰(▽)╯ github地址&#xff1a;https://github.com/liz…

【行业特化篇3】制造业简历优化指南:技术参数与标准化流程的关键词植入艺术

写在最前 作为一个中古程序猿,我有很多自己想做的事情,比如埋头苦干手搓一个低代码数据库设计平台(目前只针对写java的朋友),比如很喜欢帮身边的朋友看看简历,讲讲面试技巧,毕竟工作这么多年,也做到过高管,有很多面人经历,意见还算有用,大家基本都能拿到想要的offe…

如何在本地部署小智服务器:从源码到全模块运行的详细步骤

小智聊天机器人本地后台服务器源码全模块部署 作者&#xff1a;林甲酸 -不是小女子也不是女汉子 是大女子 更新日期&#xff1a;2025年4月29日 &#x1f3af; 前言&#xff1a;为什么要写这篇教程&#xff1f; 上周按照虾哥小智服务器的教程去部署本地后台&#xff0c;我用的是…

github开源项目添加开源协议,使用很简单

直接在 GitHub 网页上创建 进入你的 GitHub 仓库 打开你的项目仓库页面&#xff08;如 https://github.com/用户名/仓库名&#xff09;。 点击 "Add file" → "Create new file" 在仓库主页&#xff0c;点击右上角的 "Add file" 按钮&#xff…

8.idea创建maven项目(使用Log4j日志记录框架+Log4j 介绍)

8.idea创建maven项目(使用Log4j日志记录框架Log4j 介绍) 在 IntelliJ IDEA 的 Maven 项目中引入了 Log4j&#xff0c;并配置了日志同时输出到控制台和文件。 Log4j 提供了灵活的日志配置选项&#xff0c;可以根据项目需求调整日志级别、输出目标和格式。 1. 创建 Maven 项目 …

【和春笋一起学C++】函数——C++的编程模块

目录 1. 原型句法 2. 函数分类 3. 函数参数之按值传递 4. 数组作为函数参数 在C中&#xff0c;要使用函数&#xff0c;必须要有这三个方面&#xff1a; 函数原型&#xff0c;函数原型描述了函数到编译器的接口&#xff0c;函数原型一般放在include文件中。函数原型告诉编译…

深挖Java基础之:认识Java(创立空间/先导:Java认识)

今天我要介绍的是在Java中对Java的一些基本语法的认识与他们的运用&#xff0c;以及拟举例子说明和运用场景&#xff0c;优势和劣势&#xff0c; 注&#xff1a;本篇文章是对Java的一些基本的&#xff0c;简单的代码块的一些内容&#xff0c;后续会讲解在Java中的变量类型&…

Python+Selenium+Pytest+Allure PO模式UI自动化框架

一、框架结构 allure-report&#xff1a;测试报告base&#xff1a;定位元素封装data&#xff1a;数据log&#xff1a;日志文件page&#xff1a;页面封装文件夹report&#xff1a;缓存报告testcases&#xff1a;测试用例层utils&#xff1a;工具类run.py&#xff1a;执行文件 二…

博物馆除湿控湿保卫战:M-5J1R 电解除湿科技如何重塑文物守护的未来

在卢浮宫幽深的长廊里&#xff0c;达芬奇的《蒙娜丽莎》正经历着一场看不见的战争——不是来自时间的侵蚀&#xff0c;而是空气中无形的水分子。每一件文物都在与湿度进行着无声的抗争&#xff0c;这场抗争关乎人类文明的延续。湿度&#xff0c;这个看不见的文物杀手&#xff0…

【嘉立创EDA】如何找到曲线和直线的交点,或找到弧线和直线的交点

文章路标👉 :one: 文章解决问题:two: 主题内容:three: 参考方法be end..1️⃣ 文章解决问题 操作环境:嘉立创EDA专业版 V2.2.38 本文使用嘉立创EDA,描述如何快速找到曲线和直线交点的方法,这里的曲线包括了弧线等。本文将此过程记录,以供有需要的读者参考。 2️⃣ 主题…

大语言模型能否替代心理治疗师的深度拓展研究:fou

大语言模型能否替代心理治疗师的深度拓展研究 在科技初创企业和研究领域,大型语言模型(LLMs)用于替代心理健康服务提供者的应用备受关注。但研究人员通过对主要医疗机构治疗指南的梳理回顾,并对当前 LLMs(如 gpt-4o)进行实验评估后发现,LLMs 存在对心理疾病患者表达污名…

【linux】Chrony服务器

简介 1.1 时间的重要性 由于 IT 系统中&#xff0c;准确的计时非常重要&#xff0c;有很多种原因需要准确计时&#xff1a; 在网络传输中&#xff0c;数据包括和日志需要准确的时间戳 各种应用程序中&#xff0c;如订单信息&#xff0c;交易信息等 都需要准确的时间戳 1.2 时区…

mysql查看哪些表的自增id已超过某个值

场景 想看哪些表数据比较大&#xff0c;如果用count 比较慢&#xff0c;同时表设计如果是自增&#xff0c;有没有办法一次查出自增id已超过某值的所有表呢。 方法 SELECT AUTO_INCREMENT,TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA 库名 AND AUTO_INCRE…