我之前接触过windows下的内存映射文件,当时接触那个主要是要用它来实现程序crash之后的现场恢复。能恢复部分需要恢复部分内存的数据,这个时候内存映射文件就体现了作用,将需要的内存数据放到映射文件上,这样就可以实现了部分内存的持久化了,当然性能也是有很大的损失的。
现在有一个需求,需要linux的进程在遇到突发意外的时候能够恢复现场,读取之前的内存,这样意外重启之后能够让用户最小的损失体验。这种需求到我手上的时候,我自然想到了以前我在windows下的积累的经验,肯定有对应的内存映射来处理,我网上找了一下,自然有一个mmap来实现我所说的。一下我官网翻译了一点,并且加上了自己的理解总结了mmap的东西,作为马上要开展的工作的准备,具体能不能实现我也不太清楚
Name
mmap 的英文名是map files or devices into memeory
英文名很好的解释了他的含义,比中文名更好的理解,他是将文件映射到内存上,我们可以读写内存一样来读写这个文件
定义
#include
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
#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;
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);
}