什么是内存映射文件?

好处:

  1. 免去了打开文件关闭文件等等操作,想操作时直接操作自身的虚拟内存即可。
  2. 当要读写的文件特别大的时候,内存映射文件可以提供远比IO读写文件更好的性能。

内存映射文件

#include <iostream>
#include <Windows.h>

#define MAPPINGNAME L"共享文件"

HANDLE g_hMapFile;
LPTSTR g_lpBuff;

DWORD MappingFile(LPCWSTR lpcFile)
{
	HANDLE hFile;
	HANDLE hMapFile;
	DWORD dwFileMapSize;
	LPVOID lpAddr;

	//得到文件句柄
	hFile = CreateFile(lpcFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

	if (hFile == INVALID_HANDLE_VALUE)
	{
		std::cout << "失败" << std::endl;

		return FALSE;
	}

	//创建FileMapping对象
	hMapFile = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, MAPPINGNAME);

	if (hMapFile == NULL)
	{
		std::cout << "CreateFileMapping 失败" << std::endl;

		CloseHandle(hFile);

		return FALSE;
	}

	//映射到虚拟内存
	lpAddr = MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);

	if (lpAddr == NULL)
	{
		std::cout << "MapViewOfFile 失败" << std::endl;

		CloseHandle(hMapFile);

		CloseHandle(hFile);

		return FALSE;
	}

	//读取文件
	DWORD dwTest1 = *(PDWORD)lpAddr;

	DWORD dwTest2 = *((PDWORD)lpAddr + 0x20);

	printf("dwTest1:%X dwTest2:%X\n", dwTest1, dwTest2);

	//写文件
	*(PDWORD)lpAddr = 0x41414141;

	printf("写入:%X\n", *(PDWORD)lpAddr);

	//强制更新缓存 立即显示
	//默认为了效率不会立即显示 所以如果需要立即显示 使用该API即可
	FlushViewOfFile(((PDWORD)lpAddr), 4);

	//关闭
	UnmapViewOfFile(lpAddr);
	CloseHandle(hMapFile);
	CloseHandle(hFile);

	return TRUE;
}

int main()
{
	MappingFile(L"D:\\1.txt");

	return 0;
}

多进程内存映射文件

  1. 通过上面的代码创建对象以后就没有必要再创建了,直接打开即可(OpenFileMapping),需要注意名称一致(#define MAPPINGNAME L"共享文件")。
  2. 其次映射到虚拟内存(MapViewOfFile)。
  3. 读取数据或修改数据。
  4. 最后释放。
  1. 每个程序用到的DLL(无论是kernel32.dll、user32.dll还是ntdll.dll),本质上在物理内存中都只有一份。
  2. 操作系统不会为每个进程单独分配内存,只不过是每个进程各自映射了一份。

FILE_MAP_COPY 写拷贝

A进程和B进程,如果A进程修改的时候,会复制一份新的物理页,让A进程修改,而B进程不会受到影响。

例如:

  1. 在kernel32.dll中某个函数头下了一个断点,字节被修改为0xCC,但是其他进程并不受影响。
  2. 当资源释放时,不会写回到文件里,真正写回去的还是原来的物理内存,而不是被复制的那一份物理内存。
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐