内存文件映射原理和简单应用
来源:互联网 发布:遗传算法 实际应用 编辑:程序博客网 时间:2024/06/06 01:33
- 参考博客:http://blog.csdn.net/haiross/article/details/46875211
- 参考博客:http://blog.csdn.net/mg0832058/article/details/5890688 内存映射文件原理探究
- 硬盘上文件 的位置与进程 逻辑地址空间 中一块大小相同的区域之间的一一对应,这种对应关系纯属是逻辑上的概念,物理上是不存在的,原因是进程的逻辑地址空间本身就是不存在的,在内存映射的过程中,并没有实际的数据拷贝,文件没有被载入内存,只是逻辑上被放入了内存,具体到代码,就是建立并初始化了相关的数据结构(struct address_space),这个过程有系统调用mmap()实现,所以建立内存映射的效率很高。mmap将一个文件或者其它对象映射进内存,mmap必须以PAGE_SIZE为单位进行映射,而内存也只能以页为单位进行映射,若要映射非PAGE_SIZE整数倍的地址范围,要先进行内存对齐,强行以PAGE_SIZE的倍数大小进行映射。
- mmap()会返回一个指针ptr,它指向进程逻辑地址空间中的一个地址,这样以后,进程无需再调用read或write对文件进行读写,而只需要通过ptr就能够操作文件。但是ptr所指向的是一个逻辑地址,要操作其中的数据,必须通过MMU(内存管理单元)将逻辑地址转换成物理地址,这个过程与内存映射无关。
前面讲过,建立内存映射并没有实际拷贝数据,这时,MMU在地址映射表中是无法找到与ptr相对应的物理地址的,也就是MMU失败,将产生一个缺页中断,缺页中断的中断响应函数会在swap中寻找相对应的页面,如果找不到(也就是该文件从来没有被读入内存的情况),则会通过mmap()建立的映射关系,从硬盘上将文件读取到物理内存中,这个过程与内存映射无关。
如果在拷贝数据时,发现物理内存不够用,则会通过虚拟内存机制(swap)将暂时不用的物理页面交换到硬盘上,如图1中过程4所示。这个过程也与内存映射无关。
效率:从代码层面上看,从硬盘上将文件读入内存,都要经过文件系统进行数据拷贝,并且数据拷贝操作是由文件系统和硬件驱动实现的,理论上来说,拷贝数据的效率是一样的。但是通过内存映射的方法访问硬盘上的文件,效率要比read和write系统调用高,这是为什么呢?原因是read()是系统调用,其中进行了数据拷贝,它首先将文件内容从硬盘拷贝到内核空间的一个缓冲区,然后再将这些数据拷贝到用户空间,在这个过程中,实际上完成了 两次数据拷贝 ;而mmap()也是系统调用,如前所述,mmap()中没有进行数据拷贝,真正的数据拷贝是在缺页中断处理时进行的,由于mmap()将文件直接映射到用户空间,所以中断处理函数根据这个映射关系,直接将文件从硬盘拷贝到用户空间,只进行了 一次数据拷贝 。因此,内存映射的效率要比read/write效率高。
- 创建文件映射示例:
- #include <iostream>
- #include <fcntl.h>
- #include <io.h>
- #include <afxwin.h>
- using namespace std;
- int main()
- {
- //开始
- //1.获得文件句柄 创建一个文件内核对象
- HANDLE hFile=CreateFile( //失败返回INVALID_HANDLE_VALUE
- "c:\\test.dat", //文件名
- GENERIC_READ|GENERIC_WRITE, //对文件进行读写操作,文件权限,
- FILE_SHARE_READ|FILE_SHARE_WRITE, //共享模式
- NULL, //安全属性
- OPEN_EXISTING, //打开已存在文件
- FILE_ATTRIBUTE_NORMAL, //文件或设备属性或标志
- NULL); //模板模式
- //返回值size_high,size_low分别表示文件大小的高32位/低32位
- DWORD size_low,size_high;
- size_low= GetFileSize(hFile,&size_high);
- //2.创建文件的内存映射文件, 创建一个文件映射内核对象
- HANDLE hMapFile=CreateFileMapping(
- hFile, //文件名
- NULL, //安全属性
- PAGE_READWRITE, //对映射文件进行读写
- size_high,
- size_low, //这两个参数共64位,所以支持的最大文件长度为16EB ,一共要映射多少到内存中
- L"MyFileMap"); //映射的文件名字,其他进程,可通过此名字打开共享文件
- if(hMapFile==NULL) //失败返回NULL
- {
- AfxMessageBox("Can't create file mapping.Error%d:\n", GetLastError());
- CloseHandle(hFile);
- return 0;
- }
- //3.把文件数据映射到进程的地址空间
- void* pvFile=MapViewOfFile( //失败返回NULL
- hMapFile, //文件映射的句柄
- FILE_MAP_READ|FILE_MAP_WRITE, //权限
- 0, //高位偏移
- 0, //低位偏移
- 0); //一次映射多少 64K,如果是0,则映射从偏移量到文件末尾。
- unsigned char *p=(unsigned char*)pvFile;
- //至此,就获得了外部文件test.dat在内存地址空间的映射,
- //4.用指针p"折磨"这个文件了
- CString s;
- p[size_low-1]='!';
- p[size_low-2]='X'; //修改该文件的最后两个字节(文件大小<4GB高32位为0)
- s.Format("%s",p);
- //读文件的最后3个字节
- AfxMessageBox(s);
- //5.结束
- //UnmapViewOfFile(pvFile); //撤销映射
- //CloseHandle(hFile); //关闭文件
- return 0;
- }
- 打开文件映射示例:
- #include<iostream>
#include<Windows.h>
using namespace std;
int main()
{
char szBuf[100];
//1.打开文件映射对象
//权限,继承性,名字
HANDLE hFileMap = OpenFileMapping(FILE_MAP_ALL_ACCESS,NULL,L"MyFileMap");
if(NULL == hFileMap) return 0;
//2.将文件映射到进程地址空间
char * pStartAddress = (char*)MapViewOfFile(hFileMap,FILE_MAP_ALL_ACCESS,0,0,0);
//3.取出文件内容
memcpy(szBuf,pStartAddress,100);
//4.取消映射
UnmapViewOfFile(hFileMap);
system("pause");
return 0;
}
阅读全文
1 0
- 内存文件映射原理和简单应用
- 内存映射文件原理
- 内存映射文件原理
- 内存映射文件原理
- 内存映射文件原理
- 内存映射文件原理
- 内存映射文件原理
- 内存映射文件原理探索
- 内存映射文件原理探索
- 内存映射文件原理探索
- 内存映射文件原理探索
- 内存映射文件原理探索
- 内存映射文件原理探索
- 内存映射文件原理探索
- 内存映射文件原理探索
- 内存映射文件原理探索
- 内存映射文件原理探索
- 内存映射文件原理探索
- JDBC基本概念
- 浏览器PC端自定义滚动条样式-vue-bar
- 集训 第一天 三分 结构体排序
- spring boot1.5.X以上版本@ConfigurationProperties注解没有location属性后的替代用法
- JDBC学习笔记
- 内存文件映射原理和简单应用
- git-子模块subtree
- [编程题] DNA片段
- C++11新特性:Lambda函数(匿名函数)
- How to create and kill processes on remote PC
- 离线安装chrome插件Postman总结
- 从《Unity5.X从入门到精通》上扒来的基础知识(一)
- Java跳出循环-break和continue语句
- 强化练习3:判断闰年