系列文章目录

文章目录

  • 系列文章目录
  • 一、mmap简介
  • 二、mmap
    • 1.功能
    • 2.头文件
    • 3.函数声明
    • 4.函数参数
    • 5.返回值
    • 6.系统调用
  • 总结

一、mmap简介

mmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,即完成了对文件的操作而不必再调用read,write等系统调用函数。相反,内核空间对这段区域的修改也直接反映用户空间,从而可以实现不同进程间的文件共享

二、mmap

1.功能

mmap()必须以PAGE_SIZE(页) 为单位进行映射,而内存也只能以页为单位进行映射,若要映射非PAGE_SIZE整数倍的地址范围,要先进行内存对齐,强行以PAGE_SIZE的倍数大小进行映射。
mmap操作提供了一种机制,让用户程序直接访问设备内存,这种机制,相比较在用户空间和内核空间互相拷贝数据,效率更高。在要求高性能的应用中比较常用。
面向流的设备不能进行mmap,mmap的实现和硬件有关。

2.头文件

 #include <sys/mman.h>

3.函数声明

void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
int munmap(void *start, size_t length);

4.函数参数

  • start:映射区的开始地址,设置为0时表示由系统决定映射区的起始地址。
  • length:映射区的长度。
  • prot:期望的内存保护标志,不能与文件的打开模式冲突。是以下的某个值,可以通过or运算(“|”)合理地组合在一起。
   PROT_EXEC //页内容可以被执行PROT_READ //页内容可以被读取PROT_WRITE //页可以被写入PROT_NONE //页不可访问
  • flags:指定映射对象的类型,映射选项和映射页是否可以共享。它的值可以是一个或者多个以下位的组合体。
   MAP_FIXED //使用指定的映射起始地址,如果由start和len参数指定的内存区重叠于现存的映射空间,重叠部分将会被丢弃。如果指定的起始地址不可用,操作将会失败。//并且起始地址必须落在页的边界上。MAP_SHARED //与其它所有映射这个对象的进程共享映射空间。对共享区的写入,相当于输出到文件。直到msync()或者munmap()被调用,文件实际上不会被更新。MAP_PRIVATE //建立一个写入时拷贝的私有映射。内存区域的写入不会影响到原文件。这个标志和以上标志是互斥的,只能使用其中一个。MAP_DENYWRITE //这个标志被忽略。MAP_EXECUTABLE //同上MAP_NORESERVE //不要为这个映射保留交换空间。当交换空间被保留,对映射区修改的可能会得到保证。当交换空间不被保留,同时内存不足,对映射区的修改会引起段违例信号。MAP_LOCKED //锁定映射区的页面,从而防止页面被交换出内存。MAP_GROWSDOWN //用于堆栈,告诉内核VM系统,映射区可以向下扩展。MAP_ANONYMOUS //匿名映射,映射区不与任何文件关联。MAP_ANON //MAP_ANONYMOUS的别称,不再被使用。MAP_FILE //兼容标志,被忽略。MAP_32BIT //将映射区放在进程地址空间的低2GB,MAP_FIXED指定时会被忽略。当前这个标志只在x86-64平台上得到支持。MAP_POPULATE //为文件映射通过预读的方式准备好页表。随后对映射区的访问不会被页违例阻塞。MAP_NONBLOCK //仅和MAP_POPULATE一起使用时才有意义。不执行预读,只为已存在于内存中的页面建立页表入口。
  • fd:有效的文件描述词。一般是由open()函数返回,其值也可以设置为-1,此时需要指定flags参数中的MAP_ANON,表明进行的是匿名映射。
  • offset:被映射对象内容的起点。

5.返回值

成功执行时,mmap()返回被映射区的指针,munmap()返回0。
失败时,mmap()返回MAP_FAILED[其值为(void *)-1],munmap返回-1。
errno被设为以下的某个值:

 EACCES:访问出错EAGAIN:文件已被锁定,或者太多的内存已被锁定EBADF:fd不是有效的文件描述词EINVAL:一个或者多个参数无效ENFILE:已达到系统对打开文件的限制ENODEV:指定文件所在的文件系统不支持内存映射ENOMEM:内存不足,或者进程已超出最大内存映射数量EPERM:权能不足,操作不允许ETXTBSY:已写的方式打开文件,同时指定MAP_DENYWRITE标志SIGSEGV:试着向只读区写入SIGBUS:试着访问不属于进程的内存区

6.系统调用

(1)mmap()系统调用使得进程之间通过映射同一个普通文件实现共享内存。
普通文件被映射到进程地址空间后,进程可以向访问普通内存一样对文件进行访问,不必再调用read(),write()等操作。
注:实际上,mmap()系统调用并不是完全为了用于共享内存而设计的。它本身提供了不同于一般对普通文件的访问方式,进程可以像读写内存一样对普通文件的操作。
而Posix或SystemV的共享内存IPC则纯粹用于共享目的,当然mmap()实现共享内存也是其主要应用之一。
系统调用mmap()用于共享内存的两种方式:

  • 使用普通文件提供的内存映射
    适用于任何进程之间,此时,需要打开或创建一个文件,然后再调用mmap();典型调用代码如下:
   fd=open(name, flag, mode); if(fd<0) ... ptr=mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
  • 使用特殊文件提供匿名内存映射
    适用于具有亲缘关系的进程之间;由于父子进程特殊的亲缘关系,在父进程中先调用mmap(),然后调用fork()。
    那么在调用fork()之后,子进程继承父进程匿名映射后的地址空间,同样也继承mmap()返回的地址,这样,父子进程就可以通过映射区域进行通信了。
    注意,这里不是一般的继承关系。一般来说,子进程单独维护从父进程继承下来的一些变量。而mmap()返回的地址,却由父子进程共同维护。
    对于具有亲缘关系的进程实现共享内存最好的方式应该是采用匿名内存映射的方式。此时,不必指定具体的文件,只要设置相应的标志即可。

(2) int munmap( void * addr, size_t len )
该调用在进程地址空间中解除一个映射关系,addr是调用mmap()时返回的地址,len是映射区的大小。当映射关系解除后,对原来映射地址的访问将导致段错误发生。
(3)int msync ( void * addr , size_t len, int flags)
一般说来,进程在映射空间的对共享内容的改变并不直接写回到磁盘文件中,往往在调用munmap()后才执行该操作。可以通过调用msync()实现磁盘上文件内容与共享内存区的内容一致。

总结

由上文讨论可知,mmap优点共有一下几点:

1、对文件的读取操作跨过了页缓存,减少了数据的拷贝次数,用内存读写取代I/O读写,提高了文件读取效率。

2、实现了用户空间和内核空间的高效交互方式。两空间的各自修改操作可以直接反映在映射的区域内,从而被对方空间及时捕捉。

3、提供进程间共享内存及相互通信的方式。不管是父子进程还是无亲缘关系的进程,都可以将自身用户空间映射到同一个文件或匿名映射到同一片区域。从而通过各自对映射区域的改动,达到进程间通信和进程间共享的目的。同时,如果进程A和进程B都映射了区域C,当A第一次读取C时通过缺页从磁盘复制文件页到内存中;但当B再读C的相同页面时,虽然也会产生缺页异常,但是不再需要从磁盘中复制文件过来,而可直接使用已经保存在内存中的文件数据。

4、可用于实现高效的大规模数据传输。内存空间不足,是制约大数据操作的一个方面,解决方案往往是借助硬盘空间协助操作,补充内存的不足。但是进一步会造成大量的文件I/O操作,极大影响效率。这个问题可以通过mmap映射很好的解决。换句话说,但凡是需要用磁盘空间代替内存的时候,mmap都可以发挥其功效。

C语言 mmap函数相关推荐

  1. linux mmap 函数详解,mmap函数详解与代码实操

    icon1.jpg mmap 函数是 unix/linux下的系统调用. 当存在客户-服务程序中复制文件时候,其数据流如下,要经历四次数据复制,开销很大. image.png 果采用共享内存的方式,那 ...

  2. C语言:mmap函数实现

    1.认真分析mmap:是什么 为什么 怎么用: https://www.cnblogs.com/huxiao-tee/p/4660352.html 2.Mmap系列一: Mmap的实现原理和应用(及与 ...

  3. 共享内存映射之mmap()函数详解

    转 共享内存映射之mmap()函数详解 /span> 查看全文 http://www.taodudu.cc/news/show-3175071.html 相关文章: 子集生成(二进制法,逐步生成 ...

  4. C语言常用函数详细总结附示例(快速掌握)

    目录 一.简介 二.常用函数 2.1 strncpy 2.2 strcmp: 2.3 memset 2.4 strlen 2.5 memcpy 2.6 ioremap 2.7 mmap 三.其他c语言 ...

  5. 写的函数符号表里没有_你有没有想过,C语言 main 函数到底为啥这么写?

    但凡是学过C语言的人,都知道要先写main函数,然而很多时候我们看到的main函数却各有差异,这究竟是为啥?哪种是对的呢?今天我们就来聊聊main函数. 那么main函数一共有多少个版本呢? 1.ma ...

  6. R语言str_trim函数去除字符串中头部和尾部的空格

    R语言str_trim函数去除字符串中头部和尾部的空格 目录 R语言str_trim函数去除字符串中头部和尾部的空格 #导入包和库 #仿

  7. R语言sqrt函数为数值开平方根实战

    R语言sqrt函数为数值开平方根实战 目录 R语言sqrt函数为数值开平方根实战 #基本语法 #sqrt函数开平方根

  8. R语言数学函数:abs绝对值、sqrt平方根、ceiling向上近似整数、floor向下近似整数、trunc去除小数部分、round近似到指定小数位、signif近似到有效数字、三角函数、指数、对数

    R语言数学函数:abs绝对值.sqrt平方根.ceiling向上近似整数.floor向下近似整数.trunc去除小数部分.round近似到指定小数位.signif近似到有效数字.三角函数.指数.对数 ...

  9. R语言sd函数计算数值标准差实战(Standard Deviation)

    R语言sd函数计算数值标准差实战(Standard Deviation) 目录 R语言sd函数计算数值标准差实战(Standard Deviation) #基本语法 #sd

最新文章

  1. kali2020进入单模式_蚂蚁集团技术专家山丘:性能优化的常见模式及趋势
  2. SSH port forwarding: bind: Cannot assign requested address
  3. Institute for Manufacturing virtual check in part 1
  4. 实时流媒体编程基于Linux环境开发
  5. 苹果手机自带表格软件_解决手机系统自带软件无法卸载问题
  6. 论文阅读:A Randomly Accessible Lossless Compression Scheme for Time-Series Data
  7. sql server 加密_SQL Server机密–第一部分–加密基础知识和SQL Server加密功能
  8. epoll边缘触发_epoll事件通知机制详解,水平触发和边沿触发的区别
  9. 华为星环大数据_大数据平台-华为和星环
  10. 智能汽车路径规划-曲线插值法、人工势场法
  11. Godot Label 节点
  12. ArcCatalog中通过ArcSDE向Oracle数据库中导入数据
  13. 计算机视觉项目实战-基于特征点匹配的图像拼接
  14. STM32F103驱动四位共阳极数码管程序
  15. 由于navigation引起viewwillappear不被调用
  16. 照片处理:PS三步轻松实现背景虚化
  17. BUCT c语言程序设计基础第三篇10~20道题(上)
  18. CDH6.3配置安装实操
  19. 连接Oracle时报错ora-01034与ORA-27101
  20. 实验一 顺序与选择结构(Python 头歌)

热门文章

  1. oa办公系统都有哪家?
  2. 容器编排工具与 Kuberneters
  3. Tomcat详细配置(全)
  4. bzoj 3238 差异
  5. new一个对象的时候发生了什么?
  6. 拍摄UFP 单一职责原则
  7. kindeditor上传本地图片的问题
  8. Oracle安装 - Win7
  9. UDP Socket接收缓冲区与netstat Recv-Q
  10. ubuntu11.04下Discuz论坛的安装