美文网首页程序员
mmap 函数:原理与使用(含代码)

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

作者: 找不到工作 | 来源:发表于2017-08-11 17:44 被阅读903次

参考

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

介绍

除了标准的文件 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 解决。

相关文章

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

    参考 中文资料英文资料使用场景 介绍 除了标准的文件 IO,例如 open, read, write,内核还提供接...

  • 【转】linux库函数mmap()原理

    linux库函数mmap()原理 目录 1.mmap基本概念 2.mmap内存映射原理 3.mmap和常规文件操作...

  • mmap函数使用

    UNIX网络编程第二卷进程间通信对mmap函数进行了说明。该函数主要用途有三个:1、将一个普通文件映射到内存中,通...

  • Linux 共享内存函数

    mmap 函数实现共享内存 1. 匿名mmap 匿名存储映射:调用mmap函数时,指定 MAP_ANONYMOUS...

  • mmap

    简单的目录 mmap基础概念 mmap内存映射原理 mmap和常规文件操作的区别 mmap优点总结 mmap相关函...

  • mmap函数详解与代码实操

    mmap 函数是 unix/linux下的系统调用。 当存在客户-服务程序中复制文件时候,其数据流如下,要经历四次...

  • MMKV——2.原理

    1.MMKV——1.使用2.MMKV——2.原理 1. mmap高性能存取的基石 MMKV通过mmap 内存映射文...

  • swift 闭包(闭包表达式、尾随闭包、逃逸闭包、自动闭包)

    闭包是自含的函数代码块,可以在代码中被传递和使用 闭包和swift的对比 Swift 中闭包与OC的 block ...

  • 内存映射

    转自认真分析mmap:是什么 为什么 怎么用 阅读目录mmap基础概念mmap内存映射原理mmap和常规文件操作的...

  • 进程通信之内存映射

    mmap函数 解除 实例

网友评论

    本文标题:mmap 函数:原理与使用(含代码)

    本文链接:https://www.haomeiwen.com/subject/tqglrxtx.html