内存映射原理
1. 内存映射原理
1.1 什么是映射?
“映射”这个词,就和数学课上说的“一一映射”是一个意思,就是建立一种一一对应关系
1.2 内存映射原理通俗理解
通俗说就是:在这里主要是将硬盘上文件的位置与进程逻辑地址空间(其实就是32位下的4GB虚拟地址空间)中一块大小相同的区域之间的一一对应。
关于虚拟地址,请参考之前的博客:
从操作系统角度看可执行文件的装载:进程建立的3个步骤,虚拟地址空间,页错误
https://blog.csdn.net/lqy971966/article/details/106910746
1.3 内存映射原理-mmap
-
逻辑的概念
这种对应关系纯属是逻辑上的概念,物理上是不存在的,原因是进程的逻辑地址空间本身就是不存在的
在内存映射的过程中,并没有实际的数据拷贝,文件没有被载入内存,只是逻辑上被放入了内存 -
mmap
具体到代码,就是建立并初始化了相关的数据结构 (struct address_space),
这个过程有系统调用 mmap() 实现,所以建立内存映射的效率很高
mmap()会返回一个指针ptr,它指向进程逻辑地址空间中的一个地址,这样以后,只需要通过ptr就能够操作文件
2. 内存映射文件原理原理图:非常棒!!!
参考这个博客即可
https://blog.csdn.net/mengxingyuanlove/article/details/50986092
3. mmap munmap 参数详解:
#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);
-
addr:虚拟地址
如果不为 NULL,内核会在此地址创建映射;否则,内核会选择一个合适的虚拟地址。
大部分情况不指定虚拟地址,意义不大,而是让内核选择返回一个地址给用户空间使用。 -
length:表示映射到进程地址空间的大小。
-
prot:内存区域的读/写/执行属性。
下面是prot对应的参数组合:#define PROT_READ 0x1 /* page can be read /
#define PROT_WRITE 0x2 / page can be written /
#define PROT_EXEC 0x4 / page can be executed /
#define PROT_SEM 0x8 / page may be used for atomic ops /
#define PROT_NONE 0x0 / page can not be accessed /
#define PROT_GROWSDOWN 0x01000000 / mprotect flag: extend change to start of growsdown vma /
#define PROT_GROWSUP 0x02000000 / mprotect flag: extend change to end of growsup vma */ -
flags:内存映射的属性,共享、私有、匿名、文件等。
#define MAP_SHARED 0x01 /* Share changes /
/ 创建一个共享映射的区域,多个进程可以映射到一个文件.
其他进程可以看到映射内容的改变,修改后内容会同步到磁盘中。/
#define MAP_PRIVATE 0x02 / Changes are private /
/ 创建一个私有的写时复制的映射,其他进程看不到映射内容的改变,也不会同步到磁盘中。*/ -
fd:表示这是一个文件映射,fd是打开文件的句柄。
如果是文件映射,需要指定fd;匿名映射就指定一个特殊的-1。 -
offset:在文件映射时,表示相对文件头的偏移量;返回的地址是偏移量对应的虚拟地址。
参考:
https://www.cnblogs.com/arnoldlu/p/8330785.html
https://www.cnblogs.com/arnoldlu/p/9367253.html
4.代码示例
#include <sys/mman.h>
#include <sys/stat.h>
#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<error.h>
int main(int argc, char * argv[])
{
int fd, nread;
struct stat sb;
char *mapped;
//打开文件
if((fd = open(argv[1], O_RDWR)) < 0){
perror("open") ;
}
//获取文件的属性
if((fstat(fd, &sb)) == -1 ){
perror("fstat") ;
}
//将文件映射至进程的地址空间
if((mapped = mmap(NULL, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) ==(void*) -1){
perror("mmap") ;
}
//修改一个字符,同步到磁盘文件
mapped[20] = '9';
if((msync((void *)mapped, sb.st_size, MS_SYNC)) == -1){
perror("msync") ;
//释放存储映射区
if((munmap((void *)mapped,sb.st_size)) == -1){
perror("munmap");
}
}
return 0;
}
[root@localhost home]# cat test.txt
aaaaaaaaa
bbbbbbbbb
cccccccccccc
ddddddddd
执行:
[root@localhost home]# ./a.out test.txt
[root@localhost home]# cat test.txt
aaaaaaaaa
bbbbbbbbb
9ccccccccccc
ddddddddd
[root@localhost home]#
参考:
https://blog.csdn.net/whatday/article/details/89239331
参考:
原理图:
https://blog.csdn.net/mengxingyuanlove/article/details/50986092
参数详解
https://www.cnblogs.com/arnoldlu/p/9367253.html
https://www.cnblogs.com/arnoldlu/p/8330785.html
代码示例:
https://blog.csdn.net/whatday/article/details/89239331