Linux mmap讲解

0 引言

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

1 mmap简介

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

#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags,
           int fd, off_t offset);

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

为了实现这个文件映射到进程的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的工作过程

 一个map并不是一个copy。

4 代码示例

该部分代码可参考

#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#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<char*>(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的基本概念和使用。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qls315

感觉好可打赏几毛钱增强更新动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值