mmap 函数:原理与使用(含代码)

参考

中文资料
英文资料
使用场景

介绍

除了标准的文件 IO,例如 open, read, write,内核还提供接口允许应用将文件 map 到内存。使得内存中的一个字节与文件中的一个字节一一对应。

  • 优势
    • 读写文件避免了 read()write() 系统调用,也避免了数据的拷贝。
    • 除了潜在的页错误,读写 map 后的文件不引起系统调用或者上下文切换。就像访问内存一样简单。
    • 多个进程 map 同一个对象,可以共享数据。
    • 可以直接使用指针来跳转到文件某个位置,不必使用 lseek() 系统调用。
  • 劣势
    • 内存浪费。由于必须要使用整数页的内存。
    • 导致难以找到连续的内存区域
    • 创建和维护映射和相关的数据结构的额外开销。在大文件和频繁访问的文件中,这个开销相比 read write 的 copy 开销小。
mmap 原理

使用方法

函数原型为:

#include <sys/mman.h>

void * mmap (void *addr,
             size_t len,
             int prot,
             int flags,
             int fd,
             off_t offset);
  • addr
    这个参数是建议地址(hint),没有特别需求一般设为0。这个函数会返回一个实际 map 的地址。

  • len
    文件长度。

  • prot
    表明对这块内存的保护方式,不可与文件访问方式冲突。
    PROT_NONE
    无权限,基本没有用
    PROT_READ
    读权限
    PROT_WRITE
    写权限
    PROT_EXEC
    执行权限

  • flags
    描述了映射的类型。
    MAP_FIXED
    开启这个选项,则 addr 参数指定的地址是作为必须而不是建议。如果由于空间不足等问题无法映射则调用失败。不建议使用。
    MAP_PRIVATE
    表明这个映射不是共享的。文件使用 copy on write 机制映射,任何内存中的改动并不反映到文件之中。也不反映到其他映射了这个文件的进程之中。如果只需要读取某个文件而不改变文件内容,可以使用这种模式。
    MAP_SHARED
    和其他进程共享这个文件。往内存中写入相当于往文件中写入。会影响映射了这个文件的其他进程。与 MAP_PRIVATE冲突。

  • fd
    文件描述符。进行 map 之后,文件的引用计数会增加。因此,我们可以在 map 结束后关闭 fd,进程仍然可以访问它。当我们 unmap 或者结束进程,引用计数会减少。

  • offset
    文件偏移,从文件起始算起。

如果失败,mmap 函数将返回 MAP_FAILED

页面对齐

内存拥有独立权限的最小单位就是页。因此,mmap 的最小单位也是页。addroffset 参数都必须页对齐,len 会被 roundup。被 roundup 的多余的内存会以 \0 填充。对这一部分的写入操作不会影响文件。我们可以通过如下方式获取本机的页面大小:

#include <unistd.h>

long page_size = sysconf(_SC_PAGESIZE);

代码实现

因为项目需求并发写入,为了提高性能,实现了一个可以并行写入的mmap。
具体代码可以查看我的Github

遇到的问题

  1. 写入时发生错误
bus error(core dump)

stackoverflow 大佬的原话:

You are creating a new zero sized file, you can't extend the file size with mmap. You'll get a bus error when you try to write outside the content of the file.

因此使用 lseek 先把文件扩展到需要的大小。

  // solve the bus error problem:
  // we should allocate space for the file first.
  lseek(fd, size_lim_-1, SEEK_SET);
  write(fd,"",1);
  1. 文件权限设置
int fd = open(file_path_.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0644);

打开的时候忘了加 0644 设置权限。

  1. 文件大小

由于文件最初利用 lseek 扩张了一次,中间有大量的'\0'段。导致文件在验证中出错,而且打开缓慢。

// resize the file to actual size
truncate(file_path_.c_str(), cur_pos_.load());

在析构函数中增加 truncate 解决。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • UNIX网络编程第二卷进程间通信对mmap函数进行了说明。该函数主要用途有三个:1、将一个普通文件映射到内存中,通...
    宇文黎琴阅读 3,478评论 0 4
  • 如果你看完书中的所有例子,你很可能已经做完你的实验和在已经越狱的iPhone上的研究。因为和许多人一样,几乎所有的...
    fishmai0阅读 15,788评论 2 42
  • 转自认真分析mmap:是什么 为什么 怎么用 阅读目录mmap基础概念mmap内存映射原理mmap和常规文件操作的...
    扎Zn了老Fe阅读 837评论 0 3
  • 子曰:“君子不器。” 译文:孔子说:“君子不像器皿一般(只有一定的用途。)” 不器就是不成为某一个定型的人才。不被...
    甜_sweet阅读 164评论 0 1