Linux mmap讲解

0 引言

Linux 提供了非常强大的 mmap(2) 系统调用; 它使开发人员能够将任何内容直接映射到进程虚拟地址空间 (VAS)。 此内容包括文件数据、硬件设备(适配器)内存区域,或只是通用内存区域。 在本文中,我们将只关注使用 mmap(2) 将常规文件的内容映射到进程 VAS 中。

1 mmap简介

mmap(2)系统调用接口如下

#include 
void *mmap(void *addr, size_t length, int prot, int flags,
           int fd, off_t offset);

如果将文件的给定区域,从给定的偏移量offset和长度length字节映射到我们的进程虚拟地址空间 VAS; 下图描绘了想要实现的目标的简单视图:

Linux mmap讲解_第1张图片

为了实现这个文件映射到进程的VAS,可使用 mmap(2) 系统调用。

关于mmap的相关参数解释如下

fd    由open系统调用等打开的文件描述符

offset  文件映射的偏移位置

length  文件映射的长度

addr    向内核提示应该在进程 VAS 中的哪个位置创建映射; 建议在这里传递 0 (NULL),允许操作系统决定新映射的位置

prot  给定区域的内存保护标志位

flag  是一个称为标志的位掩码; 有几个标志,它们影响映射的许多属性。

上述prot具体由如下四个标志构成

PROT_NONE
没有访问权限
PROT_READ
拥有读权限
PROT_WRITE
拥有写权限
PROT_EXEC
拥有可执行权限

2 文件和匿名映射

mmap映射可分为:文件映射和匿名区映射。

mmap中的flag标记由如下概念

MAP_SHARED: 映射是共享的; 其他进程可能同时在同一个映射上工作(事实上,这是实现 IPC 机制(共享内存)的通用方式)。 在文件映射的情况下,如果写入内存区域,则更新底层文件! (您可以使用 msync(2) 来控制将内存写入刷新到底层文件。)

MAP_PRIVATE: 这建立了一个私有映射; 如果它是可写的,它意味着 COW 语义)。 私有的文件映射区域不会对底层文件进行写入。 实际上,私有文件映射在 Linux 上很常见:这正是在开始执行进程时,加载器将二进制可执行文件的文本和数据以及 进程使用的所有共享库的文本和数据。

3 mmap的优点

mmap(2) 通过在内部将包含文件数据(从存储设备读入)的内核页面缓存页面直接映射到进程虚拟地址空间来设置文件映射。这是零拷贝技术的一种实现。

下图更加形象的说明mmap的工作过程

Linux mmap讲解_第2张图片

 一个map并不是一个copy。

4 代码示例

该部分代码可参考

#include 
#include 
#include 
#include 
#include 
#include 

#define handle_error(msg) \
  do { perror(msg); exit(EXIT_FAILURE); } while (0)

int main(int argc, char *argv[]) {
  char *addr = nullptr;
  int fd{-1};

  fd = open(argv[1], O_RDONLY);
  if (fd == -1)
    handle_error("open");

  addr = static_cast(mmap(NULL, 10 * sysconf(_SC_PAGE_SIZE), PROT_READ,
                       MAP_SHARED, fd, 0));
  if (addr == MAP_FAILED)
    handle_error("mmap");

  while (true) {
    sleep(10);
  }        
  
  exit(EXIT_SUCCESS);
}

譬如我运行两次

./main test1.cc
./main test1.cc

在我的机器上通过fincore test1.cc显示如下结果

RES PAGES  SIZE FILE
 4K     1  818B test1.cc

5 总结

本文总结了mmap的基本概念和使用。

你可能感兴趣的:(linux,linux,服务器,mmap)