Linux的mmap文件内存映射机制
? ? ? ? 在讲述文件映射的概念时, 不可避免的要牵涉到虚存(SVR 4的VM). 实际上, 文件映射是虚存的中心概念, 文件映射一方面给用户提供了一组措施, 好似用户将文件映射到自己地址空间的某个部分, 使用简单的内存访问指令读写文件;另一方面, 它也可以用于内核的基本组织模式, 在这种模式种, 内核将整个地址空间视为诸如文件之类的一组不同对象的映射. 中的传统文件访问方式是, 首先用open系统调用打开文件, 然后使用read, write以及lseek等调用进行顺序或者随即的I/O. 这种方式是非常低效的, 每一次I/O操作都需要一次系统调用. 另外, 如果若干个进程访问同一个文件, 每个进程都要在自己的地址空间维护一个副本, 浪费了内存空间. 而如果能够通过一定的机制将页面映射到进程的地址空间中, 也就是说首先通过简单的产生某些内存管理数据结构完成映射的创建. 当进程访问页面时产生一个缺页中断, 内核将页面读入内存并且更新页表指向该页面. 而且这种方式非常方便于同一副本的共享.
VM是面向对象的方法设计的, 这里的对象是指内存对象: 内存对象是一个软件抽象的概念, 它描述内存区与后备测试完全正常
*??????????????? Google.com 我通常通过google搜索发现许多有用的资料
*Hope:希望越来越多的人贡献自己的力量,为科学技术发展出力
* 科技站在巨人的肩膀上进步更快!感谢有开源前辈的贡献!
*********************************************************************/
#include <sys/mman.h> /* for mmap and munmap */
#include <sys/types.h> /* for open */
#include <sys/stat.h> /* for open */
#include <fcntl.h>???? /* for open */
#include <unistd.h>??? /* for lseek and write */
#include <stdio.h>
int main(int argc, char **argv)
{
int fd;
char *mapped_mem, * p;
int flength = 1024;
void * start_addr = 0;
fd = open(argv[1], O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
flength = lseek(fd, 1, SEEK_END);
write(fd, "\0", 1); /* 在文件最后添加一个空字符,以便下面printf正常工作 */
lseek(fd, 0, SEEK_SET);
mapped_mem = mmap(start_addr, flength, PROT_READ,??????? //允许读
MAP_PRIVATE,?????? //不允许其它进程访问此内存区域
fd, 0);
/* 使用映射区域. */
printf("%s\n", mapped_mem); /* 为了保证这里工作正常,参数传递的文件名最好是一个文本文件 */
close(fd);
munmap(mapped_mem, flength);
return 0;
}
编译运行此程序:
gcc -Wall mmap.c
./a.out text_filename
上面的方法因为用了PROT_READ,所以只能读取文件里的内容,不能修改,如果换成PROT_WRITE就可以修改文件的内容了。又由于 用了MAAP_PRIVATE所以只能此进程使用此内存区域,如果换成MAP_SHARED,则可以被其它进程访问,比如下面的:
#include <sys/mman.h> /* for mmap and munmap */
#include <sys/types.h> /* for open */
#include <sys/stat.h> /* for open */
#include <fcntl.h>???? /* for open */
#include <unistd.h>??? /* for lseek and write */
#include <stdio.h>
#include <string.h> /* for memcpy */
int main(int argc, char **argv)
{
int fd;
char *mapped_mem, * p;
int flength = 1024;
void * start_addr = 0;
fd = open(argv[1], O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
flength = lseek(fd, 1, SEEK_END);
write(fd, "\0", 1); /* 在文件最后添加一个空字符,以便下面printf正常工作 */
lseek(fd, 0, SEEK_SET);
start_addr = 0x80000;
mapped_mem = mmap(start_addr, flength, PROT_READ|PROT_WRITE,??????? //允许写入
MAP_SHARED,?????? //允许其它进程访问此内存区域
fd, 0);
/* 使用映射区域. */
printf("%s\n", mapped_mem); /* 为了保证这里工作正常,参数传递的文件名最好是一个文本文 */
while((p = strstr(mapped_mem, "Hello"))) { /* 此处来修改文件 内容 */
memcpy(p, "Linux", 5);
p += 5;
}
close(fd);
munmap(mapped_mem, flength);
return 0;
}
man -a mmap 看更详细的信息