Linux下mmap

article/2025/10/23 10:26:26

目录

一.mmap简介

二.为什么需要使用mmap

三.mmap的使用

四.mmap原理


一.mmap简介

什么是mmap了?从名字上来看是memory map也就是地址映射,是一种内存映射文件的方法。mmap是一个可以将一个文件或者其它对象映射到进程的地址空间实现磁盘的地址和进程虚拟地址空间一段虚拟地址的一一对应关系。通过mmap这个系统调用我们可以让进程之间通过映射到同一个普通文件实现共享内存,普通文件被映射到进程地址空间当中之后,进程可以向访问普通内存一样对文件进行一系列操作。

二.为什么需要使用mmap

我们平时再读取文件的时候我们经常使用的方法就是read和write这两个操作系统给我们提供的方法来读写文件的时候,我们需要进行两次拷贝。由于read和write是系统调用所以我们需要先从用户态进入到内核态,然后将磁盘当中的数据拷贝到操作系统的缓冲区当中,然后再将缓冲区当中的数据拷贝到用户态当中。在这个过程当中我们进行了两次拷贝。其过程大致如下图所示:

 

但是如果我们使用mmap就可以减少一次拷贝这样带来性能上的提升是巨大的。并且我们采用内存操作比read和write要简单一些,我们不需要在用户层定义缓冲区用来保存从内核缓冲区读上来的数据,从而节约了内存的消耗。其大致流程如下:

总结:

  • 日常当中使用read或者wirte时需要进行两次拷贝一次是从文件拷贝到内核缓冲区,一次是从内核缓冲区拷贝到用户态。当我们使用mmap时可以减少第二次拷贝,一旦内核将文件映射到内存之后用户进程就可以操作这些数据了,用户进程只需要修改内核当中的内容然后通过内核的内存管理器自动将这些数据刷新到磁盘当中。
  • mmap可以内存提高性能,内核空间和用户空间共用一个缓冲区,如果多个进程正在同一个文件当中进行IO操作那么他们通过使用mmap能够共享一个内核缓冲区从而到达减少内存的消耗

三.mmap的使用

1.首先我们来看看mmap这个函数的声明:

 #include <sys/mman.h>void *mmap(void *addr, size_t length, int prot, int flags, 
int fd, off_t offset);

  函数说明:

 创建虚拟内存到物理内存或者文件的映射,下面我们来看看他的这几个参数:

  • addr:映射区的起始地址,如果是NULL系统自动分配
  • length:字节长度自动按照4kb对齐所以建议大小一般填成4kb的整数倍
  • port:映射区域的权限
  • flags:映射的标志位
  • fd:文件描述符
  • offset:文件偏移量自动按照4k对齐

下面我们来说明一下port的取值:

PORT_EXEC:映射的区域具有可执行权限

PROT_READ:映射的区域具有可读权限

PROT_WRITE:映射区域具有可写权限

PROT_NONE:映射区域不可被访问

对应flags的取值:

MAP_SHARED:对映射区域的写入操作直接反映到文件当中

MAP_FIXED:若在start上无法创建映射则失败(如果没有此标记会自动创建)

MAP_PRIVATE:对映射区域的写入操作只反映到缓冲区当中不会写入到真正的文件

MAP_ANONYMOUS:匿名映射将虚拟地址映射到物理内存而不是文件(忽略fd)

MAP_DENYWRITE:拒绝其它文件的写入操作

MAP_LOCKED:锁定映射区域保证其不被置换

返回值:函数的返回值为最后文件映射到进程空间的地址,进程可直接操作起始地址为该值的有效地址。

下面我们来演示一下映射到物理内存的案例:

#include <iostream>
#include <sys/mman.h>
#include <cstring>
#include <cerrno>
#include <cstdio>
using namespace std;
static const int SIZE = 4096;
int main()
{char *str = (char *)mmap(NULL, SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);//注意MAP_PRIVATE和MAP_SHARED//建立映射if (str == MAP_FAILED){printf("%s\n", strerror(errno));return -2;}strcpy(str, "hello ksy");puts(str);//用于取消映射munmap(str, SIZE);return 0;
}

运行结果:

 下面我们来看一下这个映射到文件该如何进行操作了,这个是特别容易错的。

下面直接给代码(注意这个代码是错误的)

#include <iostream>
#include <sys/mman.h>
#include <cstring>
#include <cerrno>
#include <cstdio>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
using namespace std;
static const int SIZE = 4096;
int main()
{int fd=open("./a.txt",O_RDWR|O_CREAT,0644);if(fd<0){printf("%s\n",strerror(errno));return -1;}char *str = (char *)mmap(NULL, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);//注意MAP_PRIVATE和MAP_SHARED//建立映射if (str == MAP_FAILED){printf("%s\n", strerror(errno));close(fd);return -2;}strcpy(str,"helloworld");close(fd);return 0;
} 

然后我们编译一下然后再看一下结果:

 很多老铁可能直接就懵逼了,没问题啊文件也有啊映射也成功了啊为什么就是映射出现错误了。下面我们来分析一下:

mmap是将虚拟内存映射到文件(物理内存)。按照我们的想法"helloworld"这个字符串应该是要被写入到文件当中。但是我们想一下我们这个文件是新创建的,好像大小是0个字节耶,那么在映射的时候好像也是映射了0个字节,所以这个文件映射过来的内存是没有的,此时我们让里面写东西崩溃了也是正常的。此时我们可以使用truncate函数对文件提前进行处理一下

下面我们来看一下truncate这个函数的原型:

 int truncate(const char *path, off_t length);

函数说明:truncate()会将参数path指定的文件大小改为参数length指定的大小。 如果原来的文件大小比参数length大,则超过的部分会被删除。我们就可以提前使用这个函数提前将文件的大小进行设置这样我们就可以向映射的这块内存进行写入了。下面我们对代码进行一下修改

#include <iostream>
#include <sys/mman.h>
#include <cstring>
#include <cerrno>
#include <cstdio>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
using namespace std;
static const int SIZE = 4096;
int main()
{int fd = open("./a.txt", O_RDWR | O_CREAT, 0644);truncate("a.txt", 1024);if (fd < 0){printf("%s\n", strerror(errno));return -1;}char *str = (char *)mmap(NULL, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);//注意MAP_PRIVATE和MAP_SHARED//建立映射if (str == MAP_FAILED){printf("%s\n", strerror(errno));close(fd);return -2;}strcpy(str, "helloworld");close(fd);return 0;
}

然后我们在运行一下代码:

此时我们发现就成功的将其写入到文件当中了.

四.mmap原理

mmap内存映射的实现过程主要分为三个阶段:

(一):进程启动映射过程并在虚拟地址空间当中为映射创建映射区域

   1.进程在用户空间调用mmap也就是上面那个函数。

   2.在当前进程的地址空间当中寻找一段连续的空虚的虚拟地址

   3.给这块虚拟地址分配一个vm_area_struct的结构并对其各个区域进行初始化

   4.将新键的虚拟结构插入到虚拟地址空间的链表或者红黑树当中

(二):实现物理内存地址和虚拟地址的映射关系

  1.为映射分配了新的虚拟地址空间之后通过待映射的文件描述符指针,在文件描述符表当中找到对应的文件描述符链接到内核已经打开的文件描述符集当中的struct_file,这个struct_file维护着这个被打开的文件的各项信息

  2.通过这个文件的结构体链接到file_operations,调用内核的mmap其函数原型为int mmap(struct file*filp,struct vm_area_struct*vma),请注意不是用户态的mmap

3.内核mmap函数通过虚拟文件系统当中的inode定位到文件的物理地址

4.通过reamp_pfn_range函数建立页表即实现了文件地址和虚拟地址的映射关系。

(三)

1.进程的读或写操作访问虚拟地址空间这一段映射地址,通过查询页表,发现这一段地址并不在物理页面上。因为目前只建立了地址映射,真正的硬盘数据还没有拷贝到内存中,因此引发缺页异常。

2.缺页异常进行一系列判断,确定无非法操作后,内核发起请求调页过程。

3.调页过程先在交换缓存空间(swap cache)中寻找需要访问的内存页,如果没有则调用nopage函数把所缺的页从磁盘装入到主存中。

4.之后进程即可对这片主存进行读或者写的操作,如果写操作改变了其内容,一定时间后系统会自动回写脏页面到对应磁盘地址,也即完成了写入到文件的过程


http://chatgpt.dhexx.cn/article/DyhWRGDC.shtml

相关文章

Android 进程间通信机制(二) mmap 原理

一. 前言 Binder中一次拷贝的实现就是利用mmap(memory mapping)内存映射机制,我们来看看它的工作原理. 二. 参考文章 下面这几篇文章建议先好好阅读一下,都是总结的很好的文章, 每个人理解可能不一样 笔者也是看了好多博客文章和B站视频讲解, 然后加上自己的理解后 输出的一…

Linux mmap讲解

0 引言 Linux 提供了非常强大的 mmap(2) 系统调用&#xff1b; 它使开发人员能够将任何内容直接映射到进程虚拟地址空间 (VAS)。 此内容包括文件数据、硬件设备&#xff08;适配器&#xff09;内存区域&#xff0c;或只是通用内存区域。 在本文中&#xff0c;我们将只关注使用…

mmap内存映射

内存映射通信 一、mmap (memory_map) 1.1 简介 存储映射I/O (Memory-mapped I/O) 使一个磁盘文件与存储空间中的一个缓冲区相映射。于是当从缓冲区中取数据&#xff0c;就相当于读文件中的相应字节。于此类似&#xff0c;将数据存入缓冲区&#xff0c;则相应的字节就自动写入…

Linux编程之mmap示例

一、问题背景 Linux下&#xff0c;针对文件读写操作&#xff0c;一般有三个步骤&#xff1a; 1&#xff09;把文件内容读入到内存中&#xff1b;调用read&#xff08;系统调用&#xff09;&#xff0c;从内核态读取文件内容到虚拟内存&#xff1b; 2&#xff09;修改内存中的内…

【mmap】深度分析mmap:是什么 为什么 怎么用 性能总结

目录 有什么用&#xff1f; 1、文件映射 2、分配内存&#xff08;匿名文件映射&#xff09; mmap基础概念 mmap内存映射原理 mmap和常规文件操作的区别 mmap优点总结 mmap相关函数 mmap使用细节 性能总结 效率对比 有什么用&#xff1f; 将一个文件或者其它对象映射…

mmap使用

linux进程虚拟地址空间中存在一段称为mmap的内存区&#xff0c;当申请用户内存较大时&#xff0c;如大于128kb&#xff0c;系统一般会通过mmap系统调用直接映射一片内存区&#xff0c;使用结束后再通过ummap系统调用归还。关于mmap的原理网上有很多文档&#xff0c;这里不再赘述…

MMAP技术

1. mmap 基础概念 mmap 即 memory map&#xff0c;也就是内存映射。 mmap 是一种内存映射文件的方法&#xff0c;即将一个文件或者其它对象映射到进程的地址空间&#xff0c;实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后&#xff…

mmap在嵌入式中的应用

大概雍正皇帝怎么也不会想到&#xff0c;自己在西历2022年的男生和女生眼里&#xff0c;会是截然不同的两种形象。 1 以我对身边同学朋友的观察&#xff0c;男生们大多爱看《雍正王朝》&#xff0c;他们眼中的雍正&#xff0c;大约是个推行了“火耗归公”、“摊丁入亩”等遏制…

Linux mmap原理

Linux mmap原理 前言Linux段页式内存管理mmapmmap内存映射原理文字概述mmap函数参数介绍源码解析1. 文件映射2. 缺页异常 mmap 和常规文件操作的区别mmap 使用的细节 小结 前言 mmap是linux操作系统提供给用户空间调用的内存映射函数&#xff0c;很多人仅仅只是知道可以通过mm…

Linux内存管理之mmap

目录 一. mmap系统调用 1. mmap系统调用 2. 系统调用munmap() 3. 系统调用msync() 二. 系统调用mmap()用于共享内存的两种方式&#xff1a; 三. mmap进行内存映射的原理 一. mmap系统调用 1. mmap系统调用 mmap将一个文件或者其它对象映射进内存。文件被映射到多…

Linux内核黑科技——mmap实现详解

前言&#xff1a;故事的开始是这样的&#xff0c;某天在脉脉上看到有人发了下面的帖子&#xff1a; 想不到 mmap 都成了黑科技了&#xff0c;为了让大家都能了解这个黑科技&#xff0c;所以还是写篇文章来详细介绍一下 mmap 的实现吧。 其实&#xff0c;源码分析是比较难写的&…

【Linux】Linux编程之 mmap解析

前言 虚拟内存系统通过将虚拟内存分割为称作虚拟页(Virtual Page&#xff0c;VP)大小固定的块&#xff0c;一般情况下&#xff0c;每个虚拟页的大小默认是4096字节。同样的&#xff0c;物理内存也被分割为物理页(Physical Page&#xff0c;PP)&#xff0c;也为4096字节。 一、…

讲一讲什么是 MMAP

1. mmap 基础概念 mmap 即 memory map&#xff0c;也就是内存映射。 mmap 是一种内存映射文件的方法&#xff0c;即将一个文件或者其它对象映射到进程的地址空间&#xff0c;实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后&#xff…

人工神经网络的应用有哪些方面,人工神经网络在生活中的应用

人工神经网络的应用 人工神经网络&#xff08;Artificial Neural Network&#xff0c;简称ANN &#xff09;&#xff0c;以数学模型模拟神经元活动&#xff0c;是基于模仿大脑神经网络结构和功能而建立的一种信息处理系统。人工神经网络具有自学习、自组织、自适应以及很强的非…

人工神经网络有哪些算法,神经网络都有哪些算法

人工神经网络分类方法 从20世纪80年代末期&#xff0c;人工神经网络方法开始应用于遥感图像的自动分类。 目前&#xff0c;在遥感图像的自动分类方面&#xff0c;应用和研究比较多的人工神经网络方法主要有以下几种&#xff1a;&#xff08;1&#xff09;BP&#xff08;BackP…

深度学习-人工神经网络概述

人工神经网络 简述 很多术语听起来很唬人&#xff0c;“人工神经网络”就属于其中之一。在很多人看来&#xff0c;我们对人类的神经系统还没有研究透彻&#xff0c;这就来了一个“人工的”神经网络&#xff0c;人脑这样复杂&#xff0c;那么人工神经网络一定相当高深莫测。如果…

人工神经网络的应用实例,人工神经网络实际应用

神经网络算法实例说明有哪些&#xff1f; 在网络模型与算法研究的基础上&#xff0c;利用人工神经网络组成实际的应用系统&#xff0c;例如&#xff0c;完成某种信号处理或模式识别的功能、构作专家系统、制成机器人、复杂系统控制等等。 纵观当代新兴科学技术的发展历史&…

人工神经网络算法实战教程

神经网络&#xff08;Artificial Neural Network&#xff0c;也称为人工神经网络&#xff0c;简称ANN&#xff09;具有通过示例学习能力。ANN是受生物神经元系统启发的的信息处理模型&#xff0c;它由大量高度互联的处理元素组成&#xff0c;这些处理元素被称神经元&#xff0c…

人工神经网络的三个要素,神经网络三要素是指

一个完整的人工神经网络包括 人工神经网络主要架构是由神经元、层和网络三个部分组成。整个人工神经网络包含一系列基本的神经元、通过权重相互连接。神经元是人工神经网络最基本的单元。 单元以层的方式组&#xff0c;每一层的每个神经元和前一层、后-层的神经元连接&#x…

人工神经网络连接方式,全连接神经网络作用

人工神经元网络的拓扑结构主要有哪几种&#xff1f;谢谢大侠~~~ 神经网络的拓扑结构包括网络层数、各层神经元数量以及各神经元之间相互连接的方式。人工神经网络的模型从其拓扑结构角度去看&#xff0c;可分为层次型和互连型。 层次型模型是将神经网络分为输入层&#xff08…