虚拟内存和物理内存
在win32操作系统下,每个进程都有它自己独立的4GB空间,是window给它分配的一个虚拟空间,并不是真正的物理空间,这4GB空间中,分为高2G和低2G,高2G是应用程序的,低2G空间是给内核应用共享的空间
可供使用的物理内存:
MmNumberOfPhysicalPages * 4 = 物理内存
虚拟内存(硬盘空间,当物理空间【内存条】不够用时,可以设置把硬盘上的一块空间拿来当做物理内存来使用)
能够识别的物理内存:
32位的系统最多可以识别物理内存为64G,但由于操作系统的限制比如XP,只能识别4G
物理页分为私有的和共享的,私有的物理页只归当前申请的进程来使用,公开的物理页所有进程都可以使用
更多的细节被操作系统封装在了底层实现,我们用户在平时的使用当中是感受不到的
更多的低层实现细节需要再深一步学习内核相关的知识才能有所体会
申请内存的两种方式:
- 通过VirtualAlloc / VirtualAllocEx申请的 Private Memory(VirtualAlloc只能在自己的进程中申请内存,VirtualAllocEx可以在别的进程申请内存)
- 通过CreateFileMapping映射的 Mapped Memory
// VirtualAlloc
LPVOID VirtualAlloc(
[in, optional] LPVOID lpAddress, // 要分配的内存区域的地址
[in] SIZE_T dwSize, // 分配的大小
[in] DWORD flAllocationType, // 分配的类型
[in] DWORD flProtect // 该内存的初始保护属性 (比如当前内存可以读可写,当前内存可以执行代码等)
);
// VirtualAllocEx
LPVOID VirtualAllocEx(
[in] HANDLE hProcess, // 要在哪个进程中申请内存的进程句柄
[in, optional] LPVOID lpAddress, // 要分配的内存区域的地址
[in] SIZE_T dwSize, // 分配的大小
[in] DWORD flAllocationType, // 分配的类型
[in] DWORD flProtect // 该内存的初始保护属性
);
#include<iostream>
#include<Windows.h>
int main() {
// 申请2K内存并具备可读可写属性
LPVOID pMyMem = VirtualAlloc(NULL,0x1000 * 2,MEM_COMMIT,PAGE_READWRITE);
// 释放
//MEM_DECOMMIT释放物理页,虚拟地址保留,MEM_RELEASE全部释放,不保留。当使用MEM_RELEASE时,dwSize参数必须为0
VirtualFree(pMyMem,0,MEM_RELEASE);
return 0;
}
释放内存:
BOOL VirtualFree(
[in] LPVOID lpAddress, // 要释放的地址
[in] SIZE_T dwSize, // 释放多大的空间
[in] DWORD dwFreeType // 释放的类型是什么(MEM_DECOMMIT释放物理页,虚拟地址保留,MEM_RELEASE全部释放,不保留。当使用MEM_RELEASE时,dwSize参数必须为0)
);
共享内存的申请方式:
// CreateFileMappingW 本身也是一个内核对象
HANDLE CreateFileMappingW(
[in] HANDLE hFile, // 把文件映射到物理页上,如果不需要填NULL
[in, optional] LPSECURITY_ATTRIBUTES lpFileMappingAttributes, // 安全描述符
[in] DWORD flProtect, // 指定文件映射对象的页面保护(当前前是可读还是可读可写,还是可执行等)
[in] DWORD dwMaximumSizeHigh, // 文件映射对象的最大大小的高阶 DWORD
[in] DWORD dwMaximumSizeLow, // 文件映射对象最大大小的低序 DWORD
[in, optional] LPCWSTR lpName // 文件映射对象的名称
);
LPVOID MapViewOfFile(
[in] HANDLE hFileMappingObject, // 映射的FileMapping的句柄
[in] DWORD dwDesiredAccess, // 对应虚拟地址的访问属性
[in] DWORD dwFileOffsetHigh, // 指定文件映射的起始偏移量(64位值,由两个 32 位参数组合)高32位
[in] DWORD dwFileOffsetLow, // 指定文件映射的起始偏移量(64位值,由两个 32 位参数组合)低32位 若偏移量为 0,表示从文件开头映射
[in] SIZE_T dwNumberOfBytesToMap // 要映射的字节数。如果为 0,则映射整个文件映射对象
);
#include<iostream>
#include<Windows.h>
HANDLE g_hMapFile;
LPTSTR g_lpBuff;
int main() {
// 创建内核对象 INVALID_HANDLE_VALUE只创建物理页,不和其它文件做关联
g_hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 0x1000, L"MyFileMapping");
// 进行映射
g_lpBuff = (LPTSTR)MapViewOfFile(g_hMapFile, FILE_MAP_WRITE, 0, 0, 0x1000);
DWORD error = GetLastError();
*(PDWORD)g_lpBuff = 0x12345678;
printf("%p", g_lpBuff);
// 关闭映射(这里只是把我们当前进程的映射关系给关闭了,物理页实际还存在)
UnmapViewOfFile(g_lpBuff);
// 关闭句柄 (只是当前进程的关联句柄被关闭,引用计数器 -1)
CloseHandle(g_hMapFile);
system("pause");
return 0;
}
- UnmapViewOfFile // 关闭映射