前言
前面几篇我们学习了用户空间的IO缓冲区,以及IO缓冲区的分散聚合IO技术.
为了减少系统调用的次数,提升系统性能,操作系统开发者门提出了这么多的缓存技术。
但是到这里这些技术同样有不足的地方:不论是读或者写文件,都需要将内容拷贝到IO缓冲区以及页高速缓冲区,这就增加了数据拷贝的次数,无形之中增加了CPU和内存的开销。
有没有一种办法既可以减少系统调用的次数同时又可以降低数据的拷贝次数呢?这里系统开发者推出了内存映射技术。
描述
将文件映射到内存:
内存数据与文件数据一一对应通过内存代替read/write系统调用接口来访问文件减少数据拷贝,减少系统调用次数,提高了系统性能
映射完成之后,用户对内存的读写即会转换为读文件的读写。
编程接口
头文件<sys/mman.h>
函数使用void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
函数功能:在用户虚地址空间创建一个和实际物理内存相映射的关系。函数参数:addr
:进程要映射的虚拟内存的起始地址,一般为NULL。操作系统会自动分配一个合适的内存地址。
length
:要映射实际的内存区域大小
prot
:内存保护标志,PROT_EXEC
,PROT_READ
,PROT_WRITE
flags
: 映射的对象类型,MAP_FIXED
,MAP_SHARED
,MAP_PRIVATE
fd
:要映射的文件描述符
offset
:文件偏移地址
mmap
:以页单位操作,参数addr
和offset
必须按页对齐(4K对齐)返回值:
成功:指向映射后的实际内存的地址
失败:MAP_FAILED
编程案例
map_write.c
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <fcntl.h>#include <sys/types.h>#include <sys/mman.h>int main(int argc,char *argv[]){int fd,i = 0;char *p_map;fd = open(argv[1],O_CREAT|O_RDWR,0666);if (-1 == fd) {printf("open failed \n");_exit(-1);}//初始化文件描述符,设置文件大小;此处也可以用ftruncate直接设置write(fd,"",14);//将fd文件映射到物理内存区域,使用MAP_SHARED标记,即映射的内存可以和其他进程共享p_map =(char *)mmap(NULL, 20, PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);if (MAP_FAILED == p_map) {printf("mmap failed \n");_exit(-1);}close(fd);//使用内存拷贝函数,将指定字符串拷贝到映射的内存区域memcpy(p_map, "hello world\n",14);sleep(5);//解除映射if (munmap(p_map,20) == -1) {printf("ummap failed \n");_exit(-1);}return 0;}
mmap_read.c
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <fcntl.h>#include <sys/mman.h>int main(int argc,char *argv[]){int fd,i = 0;char *p_map;fd = open(argv[1],O_CREAT|O_RDWR,0666);if (-1 == fd) {printf("open failed \n");_exit(-1);}p_map =(char *)mmap(NULL, 20, PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);if (MAP_FAILED == p_map) {printf("mmap failed \n");_exit(-1);}close(fd);//映射到内存之后可以直接从映射的地址中读出写入内存的数据printf("mmap read %s\n",p_map);if (munmap(p_map,20) == -1) {printf("ummap failed \n");_exit(-1);}return 0;
输出如下:
zhang@ubuntu:~/Desktop/cpp_practice$ ./write map_writezhang@ubuntu:~/Desktop/cpp_practice$ ./read map_write mmap read hello world
如果觉得《linux 文件IO与内存映射:内存映射》对你有帮助,请点赞、收藏,并留下你的观点哦!