0%

内存映射文件1

内存映射

这个可以是一个很厉害的技术,之前学过很多次相关的只是,但是都是有一些遗忘,这一次重新认真的学习一下。
与虚拟内存相比,内存映射提交到物理存储器的是来自于磁盘上的相应文件而不是系统页面文件,一旦被映射了就相当于整个文件被映射了过来,虚拟内存的页面文件我记得也就是页面大小的几倍(叫做什么粒度我也忘记了)

内存映射的目的

  1. 内存映射加载EXE和DLL,极大地缩短了启动的时间。
  2. 访问磁盘上的数据,避免了执行I/O操作,也避免了文件的内容申请缓冲区
  3. 内存之间的数据传输,像什么管道啊,油槽啊之类的各种东西好像都是基于内存映射的。
  • CreateFileMapping
  • FlushViewOfFile
  • MapViewOfFile
  • MapViewOfFileEx
  • MapViewOfFileVlm
  • OpenFileMapping
  • UnmapViewOfFile
  • UnmapViewOfFileVlm

基本上就这么几个,我还是准备分几篇博客写这个东西

创建一个内存映射内核对象CreateFileMapping

CreateFileMapping创建一个内核对象,函数的原型:

1
2
3
4
5
6
7
8
9
HANDLE CreateFileMapping(
HANDLE hFile, // handle to file to map
LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
// optional security attributes
DWORD flProtect, // protection for mapping object
DWORD dwMaximumSizeHigh, // high-order 32 bits of object size
DWORD dwMaximumSizeLow, // low-order 32 bits of object size
LPCTSTR lpName // name of file-mapping object
);
  1. hFile如果是传给他一个CreateFile的HANDLE对象的话呢,那将是打开这个文件,如果是-1的话呢,那将创建一个内存映射。
  2. 第三个参数是内存映射文件的保护属性,主要是下面这三值:PAGE_READONLY PAGE_READWRITE PAGE_WRITECOPY看名字就知道了。
  3. 三四个参数的话呢是大小,一半给他0,就是和文件一样大。
  4. 最后一个是内存映射文件的名字

打开内存映射文件OpenFileMapping

1
2
3
4
5
HANDLE OpenFileMapping(
DWORD dwDesiredAccess, // access mode
BOOL bInheritHandle, // inherit flag
LPCTSTR lpName // pointer to name of file-mapping object
);
  1. 第一个参数dwDesiredAccess就和那个打开文件感觉很像。

    • FILE_MAP_WRITE Read-write access. The target file-mapping object must have been created with PAGE_READWRITE protection. A read-write view of the file is mapped.
    • FILE_MAP_READ Read-only access. The target file-mapping object must have been created with PAGE_READWRITE or PAGE_READ protection. A read-only view of the file is mapped.
    • FILE_MAP_ALL_ACCESS Same as FILE_MAP_WRITE.
    • FILE_MAP_COPY Copy-on-write access. The target file-mapping object must have been created with PAGE_WRITECOPY protection. A copy-on-write view of the file is mapped.
  2. 第二个参数和之前那个一样就是询问一下可不可以继承

  3. 就是创建内核对象时候的名称

返回文件打开的一个句柄,失败返回NULL

分配内存地址MapViewOfFile

下一步就是为内存映射文件线性内存地址(其实就是给他一块内存),函数原型:

1
2
3
4
5
6
7
8
LPVOID MapViewOfFile(
HANDLE hFileMappingObject, // file-mapping object to map into
// address space
DWORD dwDesiredAccess, // access mode
DWORD dwFileOffsetHigh, // high-order 32 bits of file offset
DWORD dwFileOffsetLow, // low-order 32 bits of file offset
DWORD dwNumberOfBytesToMap // number of bytes to map
);
  1. 第二个参数就是一个权限类型
    • FILE_MAP_READ
    • FILE_MAP_WRITE
    • FILE_MAP_ALL_ACCESS
    • FILE_MAP_COPY
  2. 第三四个参数就是起始位置
  3. 最后一个参数给0就是映射整个文件大小

函数返回成功的话呢给的是我们一个内存地址,失败返回NULL

撤销映射UnmapViewOfFile

函数原型:

1
2
3
BOOL UnmapViewOfFile(
LPCVOID lpBaseAddress // address where mapped view begins
);

很简单就是内存地址
然后我们调用CloseHandle关闭句柄

立即刷新 FlushViewOfFile

立即刷新,如果不是的话呢就和之前的文件操作一样,关闭的时候才会(删除对象的时候才会立即刷新)。
函数原型:

1
2
3
4
BOOL FlushViewOfFile(
LPCVOID lpBaseAddress, // start address of byte range to flush
DWORD dwNumberOfBytesToFlush // number of bytes in range
);

最后一个参数还是0的话呢是全部。

先介绍的这里,之后介绍实例。