首页 > linux 文件IO与内存映射:内存映射

linux 文件IO与内存映射:内存映射

前言

前面几篇我们学习了用户空间的IO缓冲区,以及IO缓冲区的分散聚合IO技术.

为了减少系统调用的次数,提升系统性能,操作系统开发者门提出了这么多的缓存技术。

但是到这里这些技术同样有不足的地方:不论是读或者写文件,都需要将内容拷贝到IO缓冲区以及页高速缓冲区,这就增加了数据拷贝的次数,无形之中增加了CPU和内存的开销。

有没有一种办法既可以减少系统调用的次数同时又可以降低数据的拷贝次数呢?这里系统开发者推出了内存映射技术。


描述

将文件映射到内存:

  • 内存数据与文件数据一一对应
  • 通过内存代替read/write系统调用接口来访问文件
  • 减少数据拷贝,减少系统调用次数,提高了系统性能

    在这里插入图片描述

    映射完成之后,用户对内存的读写即会转换为读文件的读写。

编程接口

  • 头文件
  • 函数使用 void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
  • 函数功能:在用户虚地址空间创建一个和实际物理内存相映射的关系。
  • 函数参数:

    addr:进程要映射的虚拟内存的起始地址,一般为NULL。操作系统会自动分配一个合适的内存地址。

    length:要映射实际的内存区域大小

    prot:内存保护标志,PROT_EXEC,PROT_READ,PROT_WRITE

    flags: 映射的对象类型,MAP_FIXED,MAP_SHARED,MAP_PRIVATE

    fd:要映射的文件描述符

    offset:文件偏移地址

    mmap:以页单位操作,参数addroffset必须按页对齐(4K对齐)
  • 返回值:

    成功:指向映射后的实际内存的地址

    失败:MAP_FAILED

编程案例

map_write.c

#include 
#include 
#include 
#include 
#include 
#include 
#include int main(int argc,char *argv[]){ int fd,i = 0;char *p_map;fd = open(argv[1],O_CREAT|O_RDWR,0666);if (-1 == fd) { printf("open failed 
");_exit(-1);}//初始化文件描述符,设置文件大小;此处也可以用ftruncate直接设置write(fd,"",14);//将fd文件映射到物理内存区域,使用MAP_SHARED标记,即映射的内存可以和其他进程共享p_map =(char *)mmap(NULL, 20, PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);if (MAP_FAILED == p_map) { printf("mmap failed 
");_exit(-1);}close(fd);//使用内存拷贝函数,将指定字符串拷贝到映射的内存区域memcpy(p_map, "hello world
",14);sleep(5);//解除映射if (munmap(p_map,20) == -1) { printf("ummap failed 
");_exit(-1);}return 0;
}

mmap_read.c

#include 
#include 
#include 
#include 
#include 
#include int main(int argc,char *argv[]){ int fd,i = 0;char *p_map;fd = open(argv[1],O_CREAT|O_RDWR,0666);if (-1 == fd) { printf("open failed 
");_exit(-1);}p_map =(char *)mmap(NULL, 20, PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);if (MAP_FAILED == p_map) { printf("mmap failed 
");_exit(-1);}close(fd);//映射到内存之后可以直接从映射的地址中读出写入内存的数据printf("mmap read %s
",p_map);if (munmap(p_map,20) == -1) { printf("ummap failed 
");_exit(-1);}return 0;

输出如下:

zhang@ubuntu:~/Desktop/cpp_practice$ ./write map_write
zhang@ubuntu:~/Desktop/cpp_practice$ ./read map_write 
mmap read hello world

更多相关:

  • 更多内容,欢迎关注微信公众号:全菜工程师小辉~前言在笔者上一篇博客,详解了NIO,并总结NIO相比BIO的效率要高的三个原因,彻底搞懂NIO效率高的原理。这篇博客将针对第三个原因,进行更详细的讲解。首先澄清,零拷贝与内存直接映射并不是Java中独有的概念,并且这两个技术并不是等价的。零拷贝零拷贝是指避免在用户态(User-space)...

  • 一、预备知识—程序的内存分配  一个由c/C++编译的程序占用的内存分为以下几个部分  1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈,如果还不清楚,那么就把它想成数组,它的内存分配是连续分配的,即,所分配的内存是在一块连续的内存区域内.当我们声明变量时,那么编译器...

  • 我的爱机是一台ThinkPad T420,原装三星DDR 1333 4G内存一根,还剩一根内存位置,最近趁京东6.18促销,准备增加一根物理内存。为了确保兼容性,觉得仍然选购DDR 1333 4G内存,于是购买了金士顿这款,比如DDR3 1600的还贵。 这个安装过程完全参照该内存的网页提示进行 这里简单记录一下,以备...

  • 陪伴我多年的老本ThinkPad T420渐渐垂垂老矣, 我想更新一下可以更新的部分, 比如将2.5寸HDD更换为SSD, 将单条4G内存再增加一根, 凡此种种想法, 可能最后归结为如何获取该笔记本的硬件配置信息, 在windows下面使用鲁大师之类的检测软件, 也许很好搞定,但是在Ubuntu 14.04平台上如果办到呢? 很简单...

  • 一.内存错误出现的场景 这几天在重构ATS插件代码的过程中遇到了烦人的内存泄露问题, 周五周六连续两天通过走查代码的方法,未能看出明显的导致内存错误的代码, 同时也觉得C和C++混合编程得到一个动态库, 在一个.cpp主文件中,即用new又用malloc来动态分配内存, 可能会导致内存错误.后来网上调研和查资料发现, new和mal...

  • fifo的双向通信的方式如下图: 两个进程间的通信需要两个命名管道,分别处理一个进程的读和写 导致这种通信方式出现的根因还是由于fifo的阻塞读和阻塞写,所以这里需要使用两个管道对读写进行分别处理。 同时因为管道传输的数据为流式数据,则无法对数据进行指定标记(数据的发送者,接受者,大小。。。)。 SERVER端代码如下: /*...

  • 文章目录介绍重定向函数介绍总结 linux terminal输入如下命令,其中"|"符号即为我们上文中所说的无名管道 介绍 正如我们上文中所描述的"|“无名管道提供了具有亲缘关系的进程之间的通信,它由于直接使用系统调用,运行效率较高。则linux系统下可以大批量的使用”|"来提供命令直接输入输出的重定向。 具体sh...

  • 2019独角兽企业重金招聘Python工程师标准>>> fd_set 结构,是一个数字。 文件描述符fd的值 不能超过1024,而不是数量不能超过1024。 在开发打开句柄多的程序时,最好不要使用select。否则就使用多进程开发。 /usr/include/X11 Xpoll.h 文件 #ifndef _XPOLL_H_#...

  • 介绍 默认情况下,nginx会加载标准模块ngx_http_map_module(或称ngx_map),除非人为的在configure时添加--without-http_map_module选项。 ngx_http_map_module模块可以创建变量,这些变量的值与另外的变量值相关联。允许分类或者同时映射多个值到多个不同值并储存...

  • 文章目录1. Map的声明2. Map 元素访问带来的问题3. Map 元素的遍历4. 通过Map 实现 函数对象(C++)5. 通过Map实现一个简单Set功能...