目录

文章目录

  • 目录
  • mmap()
  • mmap 与 read/write 的性能比较
  • mmap 优点总结

mmap()

mmap() 是一个系统调用函数,本质是一种进程虚拟内存的映射方法,可以将一个文件、一段物理内存或者其它对象映射到进程的虚拟内存地址空间。实现这样的映射关系后,进程就可以采用指针的方式来读写操作这一段内存,进而完成对文件的操作,而不必再调用 read/write 等系统调用函数了。

函数原型

void *mmap(void *adrr, size_t length, int prot, int flags, int fd, off_t offset);
  • addr:建立映射区的首地址,由 Linux 内核指定。用户程序调用时直接传递 NULL。
  • length:创建映射区的大小。
  • prot:映射区的权限,有 PROT_READ、PROT_WRITE、PROT_READ|PROT_WRITE 类型。
  • flags:标志位参数,常用于设定更新物理区域、设置共享、创建匿名映射区。
    • MAP_SHARED:映射区所做的修改会反映到物理设备(磁盘)上。
    • MAP_PRIVATE:映射区所做的修改不会反映到物理设备上。
  • fd:用来建立映射区的文件描述符。
  • offset:映射文件的偏移量(4k 的整数倍),可以映射整个文件,也可以只映射一部分内容。

返回值:

  • 成功:返回创建的映射区首地址
  • 失败:MAP_FAILED 宏

与使用 malloc() 来申请内存空间一样,mmap() 建立的内存映射区在使用结束后也需要调用释放函数:

int munmap(void *addr, size_t length)

返回值:

  • 成功:0
  • 失败:-1

mmap 与 read/write 的性能比较

对一个存有 n 个整数的文件进行读取、+1,然后写入操作。

  • read/write 核心代码
/*read/write*/
gettimeofday(&tv1, NULL);fd = open("test_rw", O_RDWR);
read(fd, (void *)array, sizeof(int) * MAX);gettimeofday(&tv2, NULL);
printf( "Time of read: %dms\n", tv2.tv_usec-tv1.tv_usec);
gettimeofday(&tv1, NULL);for (i=0; i<MAX; ++i) {++array[i];
}write(fd, (void *)array, sizeof(int) * MAX);
close( fd );gettimeofday(&tv2, NULL);
printf( "Time of write: %dms\n", tv2.tv_usec-tv1.tv_usec );
pause();
  • mmap 核心代码
gettimeofday(&tv1, NULL);fd = open("test_mmap", O_RDWR);
array = mmap(NULL, sizeof(int) * MAX, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);for (i=0; i<MAX; ++i) {++array[i];
}munmap(array, sizeof(int) * MAX);
msync(array, sizeof(int) * MAX, MS_SYNC);
close(fd);gettimeofday(&tv2, NULL);
printf("Time of mmap: %dms\n", tv2.tv_usec-tv1.tv_usec);
pause();
  • read/write 执行结果

  • mmap 执行结果

可以看出,文件越大 read/write 就耗时越长,所以对于一些大文件 mmap 效率更高。这也联想到了 malloc 小于 128kb 用 brk 实现,大于用 mmap 实现。

为什么对于大文件而言 mmap 的效率要高于 read/write

先回顾一下调用 read/write 进行的常规的文件系统操作中,函数的调用过程:

  1. 进程发起读文件请求。
  2. 内核通过查找进程文件符表,定位到内核已打开文件集上的文件信息,从而找到此文件的 inode。
  3. inode 在 address_space 上查找要请求的文件页是否已经缓存在页缓存中。如果存在,则直接返回这片文件页的内容。
  4. 如果不存在,则通过 inode 定位到文件磁盘地址,将数据从磁盘复制到页缓存。之后再次发起读页面过程,进而将页缓存中的数据发给用户进程。

所以,总结来说,常规的文件操作为了提高读写效率和保护磁盘,使用了页缓存机制。这样造成读文件时需要先将文件页从磁盘拷贝到页缓存中,由于页缓存处在内核空间,不能被用户进程直接寻址,所以还需要将页缓存中数据页再次拷贝到内存对应的用户空间中。这样,通过了两次数据拷贝过程,才能完成进程对文件内容的获取任务。写操作也是一样,待写入的 Buffer 在内核空间不能直接访问,必须要先拷贝至内核空间对应的主存,再写回磁盘中(延迟写回),也是需要两次数据拷贝。

而使用 mmap 进行的文件操作中,首先会创建新的虚拟内存区域与文件磁盘地址之间的映射关系,在之后数据访问中,如果发现内存中并无相应的数据,则发起缺页异常,通过已经建立好的映射关系,只使用一次数据拷贝就将数据从磁盘中拷贝到用户空间中,供用户态进程使用。

综上,read/write 操作需要经历磁盘文件到内核页缓存再到用户空间缓存的两次数据拷贝。而 mmap 函数只需要从磁盘文件拷贝到内核缓存,然后用户进程直接就可以通过 Share 的方式进行访问,只存在一次数据拷贝过程。因此 mmap 效率更高。所以 mmap 也常被用的 “零拷贝” 场景中。

mmap 优点总结

  1. 减少了数据的拷贝次数,用内存读写取代 I/O 读写,提高了文件读取效率。
  2. 实现了用户空间和内核空间的高效交互(映射)方式。各自的空间修改操作都会直接反映在共享(Shared)区域内,从而被对方空间及时捕捉到。
  3. 提供不同进程间共享内存及相互通信的方式。无论是父子进程,还是无亲缘关系的进程之间,都可以将自身的用户空间映射到同一个文件或匿名映射到同一片区域。从而通过各自对映射区域的改动,达到进程间通信和进程间共享的目的。例如:进程 A、B 都映射了区域 Z,当 A 第一次读取 C 时,通过缺页机制从磁盘中复制文件页到共享内存;当 B 再读 C 的相同页面时,虽然也会产生缺页异常,但是不再需要从磁盘中复制文件过来,而可直接使用已经保存在内存中的文件数据。
  4. 可用于实现高效的大规模数据传输。通常的,内存空间不足是制约大数据操作的一个方面,解决方案可以是借助硬盘空间协助操作,补充内存空间的不足。但是也会进一步的造成了大量的文件 I/O 操作,极大的影响了执行效率。这个问题可以通过 mmap 映射很好的解决,但凡需要用磁盘空间代替内存的时候,mmap 都可以发挥其功效。

Linux 操作系统原理 — 内存 — mmap 进程虚拟内存映射相关推荐

  1. Linux 操作系统原理 — 内存 — 基于 MMU 硬件单元的虚/实地址映射技术

    目录 文章目录 目录 前文列表 物理地址与虚拟地址 内存空间的组织方式 虚拟地址空间的编址 内核态地址空间 用户态地址空间 内-外存空间的交换与虚拟存储空间之间的映射关系 缺页异常 前文列表 < ...

  2. Linux 操作系统原理 — 内存 — 内存分配算法

    目录 文章目录 目录 前文列表 内存碎片 伙伴(Buddy)分配算法 Slab 算法 虚拟内存的分配 内核态内存分配 vmalloc 函数 kmalloc 用户态内存分配 malloc 申请内存 用户 ...

  3. Linux 操作系统原理 — 内存 — 基于局部性原理实现的内/外存交换技术

    目录 文章目录 目录 前文列表 基于局部性原理实现的内-外存交换技术 局部性原理 Swap 交换分区 前文列表 <Linux 操作系统原理 - 内存 - 物理存储器与虚拟存储器> < ...

  4. Linux 操作系统原理 — 内存 — 页式管理、段式管理与段页式管理

    目录 文章目录 目录 前文列表 页式管理 快表 多级页表 基于页表的虚实地址转换原理 应用 TLB 快表提升虚实地址转换速度 页式虚拟存储器工作的全过程 缺页中断 为什么 Linux 默认页大小是 4 ...

  5. Linux 操作系统原理 — 内存管理 — 虚拟地址空间

    目录 文章目录 目录 虚拟内存技术 页式内存管理技术 虚拟地址格式与页表(32bit 系统) 虚拟地址格式与页表(64bit 系统) CPU MMU 虚实地址转换 TLS 快表转换 虚拟地址空间与 C ...

  6. Linux 操作系统原理 — 内存管理 — 页式内存管理技术

    目录 文章目录 目录 虚拟内存技术 页式内存管理技术 虚拟内存技术 虚拟内存技术是操作系统实现的一种高效的物理内存管理方式,具有以下作用: 使得进程间彼此隔离:通过将物理内存和虚拟地址空间联系起来,并 ...

  7. Linux 操作系统原理 — 内存 — 物理存储器与虚拟存储器

    目录 文章目录 目录 Linux 内存管理全貌 物理存储器 虚拟存储器 Linux 内存管理全貌 物理存储器 见<计算机组成原理 - 存储系统>. 虚拟存储器 在早期的计算机系统中,程序员 ...

  8. Linux 操作系统原理 — 内存 — Cache 和 Buffer

    目录 文章目录 目录 无处不在的 Cache Cache 和 Buffer 的区别在哪里? 为什么需要缓存? Linux 的缓存机制 Page Cache 的同步机制(一致性问题) 无处不在的 Cac ...

  9. linux的原理和运用,Linux操作系统原理与应用_内存寻址

    原标题:Linux操作系统原理与应用_内存寻址 第五讲今天上线啦. 在本次课程中,陈老师详细的讲解了有关于内存寻址的演变的相关知识. 第一部分中,介绍了关于内存寻址的相关背景知识.内存寻址-操作系统设 ...

最新文章

  1. jupyter 魔法函数
  2. oracle 测试sql执行时间_通过错误的SQL来测试推理SQL的解析过程
  3. 阿里云 fatal: Authentication failed 退出码 128
  4. Linux网络编程 | Socket编程(一):Socket的介绍、UDPSocket的封装、UDP服务器/客户端的实现
  5. ftp ssl java_FTP(四)实现FTP,SSL加密
  6. [asp.net mvc 奇淫巧技] 06 - 也许你的项目同一个用户的请求都是同步的
  7. 近景摄影测量 matlab,近景摄影测量 3.ppt
  8. css建立一个简单的设备登记表,员工登记表格的CSS块
  9. Editplus 使用技巧大全
  10. 蓝牙耳机排名前十:618性价比超高的真无线蓝牙耳机推荐!
  11. SNMP 枚举工具 Snmpwalk
  12. 华为手机录制屏幕视频的详细操作
  13. Java XML教程
  14. 计算机应用powerpoint试题,《计算机应用基础》试题二
  15. 《Java 技术体系》之一:Java 技术体系概览
  16. 01背包问题动态规划
  17. 坚鹏:银行数字化转型中的金融数据治理、数据安全政策解读培训
  18. 异步请求动态加载页面
  19. 1013: 求两点间距离 Python
  20. 粒子群优化极限学习机PSOELM做数据预测 PSO-ELM优化算法预测模型

热门文章

  1. 河北师范大学C语言试题,2017年河北师范大学信息技术学院838C语言程序设计考研题库...
  2. 主板电源开关接口图解_电脑主板开机电路检修步骤及思路。
  3. 计算机科目三教学设计,信息技术-教学设计模板(科目三).pdf
  4. mac写python3_跟我读python3文档:004_mac与python3配置
  5. mysql存储过程number类型_MySQL存储过程的基本函数(三)
  6. 证照编号与所选择的主体类型不一致_你的孩子天天在用“化妆品”,如何不踩雷?...
  7. c++ 回调函数_Java中的回调机制,这篇给你整的明明白白的
  8. lstm代码_贼好理解,这个项目教你如何用百行代码搞定各类NLP模型
  9. CMU贺斌教授团队提出FAST-IRES技术,利用高密度EEG产生脑信号源的动态图像
  10. AAAI第二届“AI诺奖”出炉,百万美元奖金颁给批判黑箱、推广可解释AI的杜克大学女教授...