Linux下mmap
目录
一.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.之后进程即可对这片主存进行读或者写的操作,如果写操作改变了其内容,一定时间后系统会自动回写脏页面到对应磁盘地址,也即完成了写入到文件的过程
Linux下mmap相关推荐
- DM6467之视频采集(Linux)下MMAP
做dsp6467是在linux下做视频采集,仅ARM端 一共有三种视频采集方式: 1)使用read.write方式:直接使用 read 和 write 函数进行读写.这种方式最简单,但是这种方式会在用 ...
- mmap函数linux,linux下mmap()函数
最近看完了Beginning Linux Programming的文件系统部分,感觉还是有颇多收获,对系统调用有了一个初步的概念,同时也了解了标准I/O库和Linux系统调用函数的关系.不过关于mma ...
- linux下mmap的使用
http://blog.csdn.net/adcxf/archive/2009/03/14/3989725.aspx 共 享内存可以说是最有用的进程间通信方式,也是最快的IPC形式.两个不同进程A.B ...
- Linux下IPC方式之共享存储映射(mmap)
Linux下IPC方式之共享存储映射(mmap) 1. 共享存储映射(mmap) 2. mmap九问 3. mmap实现父子进程通信 4. 匿名映射 5. mmap实现无血缘进程通信 1. 共享存储映 ...
- Qt/Linux 下的摄像头捕获(Video4Linux2)
Linux下使用各种设备是一件令人兴奋的事情.在Unix的世界里,用户与硬件打交待总是简单的.最近笔者在Linux下搞了摄像头的开发,有一点感想发于此处. Linux中操作一个设备一般都是打开(ope ...
- linux系统编程需要什么,若想成为一名Linux下编程高手,必须能对各种系统调用有透彻的了解...
原标题:若想成为一名Linux下编程高手,必须能对各种系统调用有透彻的了解 什么是系统调用? Linux内核中设置了一组用于实现各种系统功能的子程序,称为系统调用.用户可以通过系统调用命令在自己的应用 ...
- linux下的c库函数大全
linux下的c库函数大全,虽然没有函数描述,但是最起码可以知道分类,就可以去 man 了 Linux C函数库参考手册 第1章字符测试函数 isalnum(测试字符是否为英文字母或数字) isalp ...
- linux下configure命令详解
Linux环境下的软件安装,并不是一件容易的事情;如果通过源代码编译后在安装,当然事情就更为复杂一些;现在安装各种软件的教程都非常普遍;但万变不离其中,对基础知识的扎实掌握,安装各种软件的问题就迎刃而 ...
- Linux 下的五种 IO 模型
Linux 下的五种 IO 模型 来源:decaywood's Blog 概念说明 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2 ...
最新文章
- Pandas选择一列或者多列数据
- Python天天练2--面向对象+异常
- FarBox--另类有趣的网站服务【转】
- mysql 修改配置生效_linux下面MySQL变量修改及生效
- java增加内容辅助_Eclipse代码自动提示(内容辅助content assist)
- 2018蓝桥杯省赛---java---B---3(复数幂)
- elementui更改el-table表头背景颜色和字体颜色
- 数字化浪潮下 企业如何让问题“尽在掌握”?
- HDU 2604 Queuing
- java中整形_java中怎样实现60多位整形数字的运算
- Unity工程中 .Meta 文件的来龙去脉
- coverity中碰到的错误
- Linux内核移植之DM9000网卡驱动
- wps怎么做文档分享
- Unipus-writing exercise Expository_Text_09
- 云计算机怎么打游戏,云电脑玩游戏性能怎么样?会不会卡顿
- jdt eclipse_Eclipse JDT语言服务器项目
- linux dumpe2fs命令
- mysql不能持久存储数据的是_数据持久化存储
- HCI-人机交互概论 (一)
热门文章
- 【华为上机真题】汽水瓶
- 互联网竞争,本质是渠道之争(从360、小米手机到淘宝...)
- c语言如何使一行抹去,c语言,clrscr();怎么清除指定的内容,不是页面都清除掉。比如第一行是标题,我只想清除第二行...
- LinkSLA亮相2022 GOPS全球运维大会 共话智能运维发展新风向
- 【每日一题】相等的有理数
- 使用Vue构建前端页面
- Linux挂载(mount)后没有读写权限
- mysql对xa的支持_Mysql对XA的支持
- 越秀商投定义楼宇新生态 菁英汇聚最美中轴体验馆
- 手把手教你在VirtualBox中与主机共享文件夹