mmap的用法

mmap的用法

mmap的用法 #

mmap是申请堆内存的系统调用,它是最重要的内存管理接口。mmap 的头文件和原型如下所示:

#include <unistd.h>
#include <sys/mman.h>
void* mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset);
  • addr 代表该区域的起始地址;
  • length 代表该区域长度;
  • prot 描述了这块新的内存区域的访问权限;
  • flags 描述了该区域的类型;
  • fd 代表文件描述符;
  • offset 代表文件内的偏移值。

mmap 的功能非常强大,根据参数的不同,它可以用于创建共享内存,也可以创建文件映射区域用于提升 IO 效率,还可以用来申请堆内存。决定它的功能的,主要是 prot, flags 和 fd 这三个参数,分别来看看。

prot 的值可以是以下四个常量的组合:

  • PROT_EXEC 表示这块内存区域有可执行权限,意味着这部分内存可以看成是代码段,它里面存储的往往是 CPU 可以执行的机器码。
  • PROT_READ 表示这块内存区域可读。
  • PROT_WRITE 表示这块内存区域可写。
  • PROT_NONE 表示这块内存区域的页面不能被访问。

而 flags 的值可取的常量比较多,你可以通过 man mmap 查看,这里我只列举一下最重要的四种可取值常量:

  • MAP_SHARED 创建一个共享映射的区域,多个进程可以通过共享映射的方式,来共享同一个文件。这样一来,一个进程对该文件的修改,其他进程也可以观察到,这就实现了数据的通讯。
  • MAP_PRIVATE 创建一个私有的映射区域,多个进程可以使用私有映射的方式,来映射同一个文件。但是,当一个进程对文件进行修改时,操作系统就会为它创建一个独立的副本,这样它对文件的修改,其他进程就看不到了,从而达到映射区域私有的目的。
  • MAP_ANONYMOUS 创建一个匿名映射,也就是没有关联文件。使用这个选项时,fd 参数必须为空。
  • MAP_FIXED 一般来说,addr 参数只是建议操作系统尽量以 addr 为起始地址进行内存映射,但如果操作系统判断 addr 作为起始地址不能满足长度或者权限要求时,就会另外再找其他适合的区域进行映射。如果 flags 的值取是 MAP_FIXED 的话,就不再把 addr 看成是建议了,而是将其视为强制要求。如果不能成功映射,就会返回空指针。

通常,使用私有匿名映射来进行堆内存的分配。

再来看参数 fd。当参数 fd 不为 0 时,mmap 映射的内存区域将会和文件关联,如果 fd 为 0,就没有对应的相关文件,此时就是匿名映射,flags 的取值必须为 MAP_ANONYMOUS。

mmap 这个系统调用的能力非常强大,先来了解一下它最常见的用法。根据映射的类型,mmap 有四种最常用的组合:

其中,私有匿名映射常用于分配内存,也就是上文讲的申请堆内存。

总结来说:

  • 私有匿名映射,用于分配堆空间;
  • 共享匿名映射,用于父子进程之间通讯;
  • 私有文件映射,用于加载动态链接库;
  • 共享文件映射,用于多进程之间通讯。

Viewpoint #

From #

03 | 内存布局:应用程序是如何安排数据的?