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结构的指针,在该结构中返回有关指定页面范围的信息。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
2018-03-29 C++反汇编(一)