linux内存映射 mmap munmap

来源:互联网 发布:雷电模拟器mac版本 编辑:程序博客网 时间:2024/05/20 09:46

我之前接触过windows下的内存映射文件,当时接触那个主要是要用它来实现程序crash之后的现场恢复。能恢复部分需要恢复部分内存的数据,这个时候内存映射文件就体现了作用,将需要的内存数据放到映射文件上,这样就可以实现了部分内存的持久化了,当然性能也是有很大的损失的。

现在有一个需求,需要linux的进程在遇到突发意外的时候能够恢复现场,读取之前的内存,这样意外重启之后能够让用户最小的损失体验。这种需求到我手上的时候,我自然想到了以前我在windows下的积累的经验,肯定有对应的内存映射来处理,我网上找了一下,自然有一个mmap来实现我所说的。一下我官网翻译了一点,并且加上了自己的理解总结了mmap的东西,作为马上要开展的工作的准备,具体能不能实现我也不太清楚

Name

mmap 的英文名是map files or devices into memeory

英文名很好的解释了他的含义,比中文名更好的理解,他是将文件映射到内存上,我们可以读写内存一样来读写这个文件

定义

#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags,
  int fd, off_t offset);//用来
int munmap(void *addr, size_t length);
mmap() 该函数可以从创建进程的的虚拟内存中创建一个映射。
参数:
addr 指定我从虚拟内存中创建映射的其实地址,使用的时候一般设置成NULL
length 指定我创建内存映射的内存长度
prot 这个指定我创建内存映射使用进程的对该内存的权限,可以有多个权限。PROT_EXEC,PROT_READ,PROT_ERITE以及PROT_NONE意思很简单,对应的执行,读,写权限。这个模式权限不能跟你对应的文件相冲突,如果这边配置可写,但是打开的文件是不可写,就会出现问题
flag 指定映射对象的类型,有很多含义。这个文件主要用来设置该映射文件的所属进程,以及其余进程打开这个文件的权限设定
例如WAP_SHARED 当进程对这个映射区域写入数据会复制到文件内,并且其他进程可以读取修改的数据,当然这个是我需要的。
fd 这个指定我内存映射关联的物理文件,一般是一个文件打开的句柄,fopen文件的时候的返回值。
offset 被映射文件的偏移值,这个可以直接填0

返回值

如果成功,mmap返回一个指向已经映射的内存区域首地址。如果错误返回MAP_FAILED((void*)-1),错误可以通过errno来查询错误。

应用场景

目的:内存的持久化
现场环境:一个比较大map需要内存持久化,map里面有指针。直接拷贝内存不可行。并且该map命中率较高,更新频繁,但是保持定时更新。持久化村是内存不需要实时持久化。
计划实现:

1.创建映射文件

进程内创建映射文件,并且保持可读写,并且落地到相关文件中,独立该文件到IO操作并不大的盘符

2.实现

启动定时器,定时器中将map内存连续化,即转换json,将json写入到内存映射中

3.启动进程

读取内存映射,并且解析,读入到map中,实现现场的恢复

官方例子

 #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;
           int fd;
           struct stat sb;
           off_t offset, pa_offset;
           size_t length;
           ssize_t s;
           if (argc < 3 || argc > 4) {
               fprintf(stderr, "%s file offset [length]\n", argv[0]);
               exit(EXIT_FAILURE);
           }
           fd = open(argv[1], O_RDONLY);
           if (fd == -1)
               handle_error("open");
           if (fstat(fd, &sb) == -1)           /* To obtain file size */
               handle_error("fstat");
           offset = atoi(argv[2]);
           pa_offset = offset & ~(sysconf(_SC_PAGE_SIZE) - 1);
               /* offset for mmap() must be page aligned */
           if (offset >= sb.st_size) {
               fprintf(stderr, "offset is past end of file\n");
               exit(EXIT_FAILURE);
           }
           if (argc == 4) {
               length = atoi(argv[3]);
               if (offset + length > sb.st_size)
                   length = sb.st_size - offset;
                       /* Can't display bytes past end of file */
           } else {    /* No length arg ==> display to end of file */
               length = sb.st_size - offset;
           }
           addr = mmap(NULL, length + offset - pa_offset, PROT_READ,
                       MAP_PRIVATE, fd, pa_offset);
           if (addr == MAP_FAILED)
               handle_error("mmap");
           s = write(STDOUT_FILENO, addr + offset - pa_offset, length);
           if (s != length) {
               if (s == -1)
                   handle_error("write");
               fprintf(stderr, "partial write");
               exit(EXIT_FAILURE);
           }
          munmap(addr, length + offset - pa_offset);
           close(fd);
           exit(EXIT_SUCCESS);
       }