Windows上的文件映射与内存共享

一、概念

文件映射:将磁盘上的文件映射入内存,所谓映射就是先在内存中分配一块内存预备使用,在使用的时候再将文件加载入内存。

内存共享:在进程A中开辟一块内存,然后将这块内存映射到进程B中(进程B实际也会开辟一块内存空间),进程A与B访问它们物理上各自开辟的空间,但是逻辑上是访问同一块内存。

二、文件映射

先使用CreateFile或OpenFile打开文件,获得文件句柄,使用CreateFileMapping创建一个文件映射对象并获得该对象的句柄,使用文件映射对象的句柄调用MapViewOfFileEx创建文件映射视图并开辟一块内存空间供文件映射使用(也可以指定分配哪块内存,最后一个参数指定地址即可,也可以为NULL,这样是操作系统选定分配的地址)。

PS:指定的lpBaseAddress必须是系统内存分配粒度的倍数,否则函数会失败。

使用到的函数,如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
HANDLE CreateFileMappingA(
  [in]           HANDLE                hFile,//打开的文件句柄
  [in, optional] LPSECURITY_ATTRIBUTES lpFileMappingAttributes,//NULL
  [in]           DWORD                 flProtect,//权限
  [in]           DWORD                 dwMaximumSizeHigh,//0
  [in]           DWORD                 dwMaximumSizeLow,//buffer大小
  [in, optional] LPCSTR                lpName   //映射对象的名字
);
 
LPVOID MapViewOfFileEx(
  [in]           HANDLE hFileMappingObject,
  [in]           DWORD  dwDesiredAccess,//权限
  [in]           DWORD  dwFileOffsetHigh, //0
  [in]           DWORD  dwFileOffsetLow,  //0
  [in]           SIZE_T dwNumberOfBytesToMap,//buffer大小
  [in, optional] LPVOID lpBaseAddress   //指定在地址处分配空间
);
 
BOOL UnmapViewOfFile(
  [in] LPCVOID lpBaseAddress
);

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int _tmain(void)
{
    HANDLE hMapFile;
    LPCTSTR pBuf;
    DWORD size;
 
    hMapFile = CreateFileMapping(
         INVALID_HANDLE_VALUE,    // use paging file
         NULL,                    // default security
         PAGE_READWRITE | SEC_COMMIT | SEC_LARGE_PAGES,
         0,                       // max. object size
         size,                    // buffer size
         szName);                 // name of mapping object
 
    pBuf = (LPTSTR) MapViewOfFile(hMapFile,          // handle to map object
         FILE_MAP_ALL_ACCESS | FILE_MAP_LARGE_PAGES, // read/write permission
         0,
         0,
         BUF_SIZE);
 
    UnmapViewOfFile(pBuf);
    CloseHandle(hMapFile);
}

  我们使用MapViewOfFileEx返回的地址进行读写映射进来的文件,在修改完毕后操作系统不会马上写回磁盘上的文件,调用UnmapViewOfFile后会写回,但是同时会销毁视图,所以我们可以使用FlushViewOfFile来进行及时的修改返回。

1
2
3
4
BOOL FlushViewOfFile(
  [in] LPCVOID lpBaseAddress,
  [in] SIZE_T  dwNumberOfBytesToFlush
);

PS:

通过映射视图修改文件时,最后修改时间戳可能不会自动更新。

文件的映射视图不能保证与 ReadFile或 WriteFile函数正在访问的文件一致。

MapViewOfFileEx可以处理远程文件,但它并不能保持它们的连贯性。

三、内存共享

当CreateFileMapping中的文件句柄为-1时,则创建的映射对象用于共享内存。

一个进程可以使用 DuplicateHandle函数将文件映射对象句柄复制到另一个进程中,或者另一个进程可以使用OpenFileMapping函数按名称打开文件映射对象 。

另一端的进程同样也需使用MapViewOfFileEx构建视图,其他的步骤与文件映射相同。

1
2
3
4
5
HANDLE OpenFileMappingW(
  [in] DWORD   dwDesiredAccess,//权限
  [in] BOOL    bInheritHandle,    //false
  [in] LPCWSTR lpName            //对象名字,与Create的相同
);

要获取视图的大小,请使用 VirtualQueryEx函数。

1
2
3
4
5
6
SIZE_T VirtualQueryEx(
  [in]           HANDLE                    hProcess,
  [in, optional] LPCVOID                   lpAddress,
  [out]          PMEMORY_BASIC_INFORMATION lpBuffer,
  [in]           SIZE_T                    dwLength
);

lpAddress指向要查询的页面区域的基地址的指针。

lpBuffer指向 MEMORY_BASIC_INFORMATION结构的指针,在该结构中返回有关指定页面范围的信息。

posted @   An2i  阅读(365)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
历史上的今天:
2018-03-29 C++反汇编(一)
点击右上角即可分享
微信分享提示