什么时候选择mmap而非read?

mmap 和 read 系统流程

拼多多优惠券 https://www.fenfaw.net/

在linux文件系统中,通常使用open(), read()读取文件,但操作系统同样提供了mmap()作为读取文件的方式,而这两者有什么不同呢?什么时候用read(), 什么时候用mmap()?

首先,read 的通常使用方法是 read(fd, buffer, size),将要读取的数据读到buffer中。这就涉及到两个步骤,read是系统调用函数,每次使用read都要进入内核态,进行上下文切换。内核首先将文件数据从磁盘读入page cache缓存,再将数据从page cache拷贝到buffer中。上下文切换和拷贝要消耗一定性能。

而如果使用 mmap 命令,VFS(虚拟文件系统)会分配对应的虚拟内存空间,记录目标文件的 inode 和其他属性,将起始虚拟地址返回给进程。当进程想要访问某部分数据时,需要进行地址翻译,但此时没有更新页表,会触发缺页中断。linux根据VMA中记录的 inode 信息,调用对应的文件系统进行处理。文件系统读取该页,返回给VFS,VFS再更新页表,返回对应的物理页。

在 mmap 之后,后续的读写操作都是在内存中进行,不需要再读磁盘和进入内核态。

mmap的优点

因此 mmap 比起 read ,有如下优势:

  1. 对于随机访问,不用频繁 lseek。因为 mmap 是将整个文件映射到虚拟空间,在读取时再按需分配物理内存。
  2. 减少后续系统调用次数。后续读文件时不需要再进入内核态,减少了上下文切换
  3. 减少数据拷贝。免去了page cache 到 buffer 的数据拷贝。
  4. 当多个进程将同一页面映射到内存时,数据可以在这些进程之间共享。对于 只读 的页面可以完全共享,需要写入的文件可以使用COW(copy on write)私有化。这样节省了大量内存。

mmap also allows the operating system to optimize paging operations. For example, consider two programs; program A which reads in a 1MB file into a buffer creating with malloc, and program B which mmaps the 1MB file into memory. If the operating system has to swap part of A's memory out, it must write the contents of the buffer to swap before it can reuse the memory. In B's case any unmodified mmap'd pages can be reused immediately because the OS knows how to restore them from the existing file they were mmap'd from. (The OS can detect which pages are unmodified by initially marking writable mmap'd pages as read only and catching seg faults, similar to Copy on Write strategy).

mmap 还可以优化操作系统分页。对于进程A、B,如果A通过 read 读取了1MB数据到buffer中,而B通过 mmap 读取1MB数据。如果OS想要把A中的 buffer 换入磁盘,首先要将buffer中的内容写入磁盘,才可以重用该物理页。而对于B中没有被修改过的 mmap 页,OS可以直接重用,因为OS可以从文件中再重新读取该页来恢复数据。

那么,如果 mmap 比起 open(),read() 有这么多优点,为什么不用 mmap 呢?对于系统来说,有优点往往意味着存在对应的缺点,这才是系统设计中的trade off。

mmap的缺点

  1. mmap 每次以页为单位从文件中读取数据,因此映射的页面大小始终是整数。对于小文件可能会造成较多的内部碎片。同时,在读取数据时也需要显式修正数据在页面中的偏移量。
  2. mmap 需要连续的虚拟内存空间用于储存文件,如果文件较大,对于32位地址空间的系统来说,可能找不到足够大的连续区域。
  3. mmap 本身开销比 read 大,因为mmap涉及更多的系统调用,需要触发缺页中断,更改虚拟内存映射。

总结

由于read 读取文件更加直观和易于理解,因此初学者依然使用 read 较多。但如果需要随机访问数据,或者和其他进程共享数据,用 mmap 不失为一个更好的选择。

你可能感兴趣的:(什么时候选择mmap而非read?)