内存管理API
概述
Windows提供了多种内存管理机制,包括堆内存、虚拟内存和内存映射文件等。不同的内存管理方式适用于不同的场景。
内存管理方式
- 堆内存(Heap):最常用,适合小粒度内存分配
- 虚拟内存(Virtual):底层操作,适合大块内存管理
- 内存映射文件(File Mapping):文件与内存映射,进程间共享
- 全局/局部内存:16位Windows遗留,已不推荐使用
堆内存管理
HeapCreate - 创建堆
| C++ |
|---|
| HANDLE HeapCreate(
DWORD flOptions, // 堆分配选项
SIZE_T dwInitialSize, // 初始大小(字节)
SIZE_T dwMaximumSize // 最大大小(字节)
);
|
参数:
- flOptions:
- 0:默认
- HEAP_GENERATE_EXCEPTIONS:分配失败时抛出异常
- HEAP_NO_SERIALIZE:不序列化访问
- dwInitialSize:初始提交大小
- dwMaximumSize:最大大小(0表示可增长)
返回值:成功返回堆句柄,失败返回NULL
示例:
| C++ |
|---|
| HANDLE hHeap = HeapCreate(0, 1024 * 1024, 0); // 创建1MB初始大小的堆
if (hHeap == NULL) {
printf("HeapCreate failed: %d\n", GetLastError());
return -1;
}
|
HeapAlloc - 分配堆内存
| C++ |
|---|
| LPVOID HeapAlloc(
HANDLE hHeap, // 堆句柄
DWORD dwFlags, // 分配选项
SIZE_T dwBytes // 分配字节数
);
|
参数:
- dwFlags:
- 0:默认
- HEAP_GENERATE_EXCEPTIONS:失败时抛出异常
- HEAP_NO_SERIALIZE:不序列化
- HEAP_ZERO_MEMORY:初始化为零
示例:
| C++ |
|---|
| // 分配内存
LPVOID pMem = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, 1024);
if (pMem == NULL) {
printf("HeapAlloc failed: %d\n", GetLastError());
HeapDestroy(hHeap);
return -1;
}
|
HeapReAlloc - 重分配堆内存
| C++ |
|---|
| LPVOID HeapReAlloc(
HANDLE hHeap, // 堆句柄
DWORD dwFlags, // 分配选项
LPVOID lpMem, // 原内存指针
SIZE_T dwBytes // 新大小
);
|
示例:
| C++ |
|---|
| // 扩展内存到2048字节
LPVOID pNewMem = HeapReAlloc(hHeap, HEAP_ZERO_MEMORY, pMem, 2048);
if (pNewMem == NULL) {
printf("HeapReAlloc failed: %d\n", GetLastError());
}
|
HeapFree - 释放堆内存
| C++ |
|---|
| BOOL HeapFree(
HANDLE hHeap, // 堆句柄
DWORD dwFlags, // 释放选项
LPVOID lpMem // 内存指针
);
|
示例:
| C++ |
|---|
| HeapFree(hHeap, 0, pMem); // 释放内存
|
HeapDestroy - 销毁堆
| C++ |
|---|
| BOOL HeapDestroy(
HANDLE hHeap // 堆句柄
);
|
示例:
| C++ |
|---|
| HeapDestroy(hHeap); // 销毁堆
|
HeapSize - 获取分配大小
| C++ |
|---|
| SIZE_T HeapSize(
HANDLE hHeap, // 堆句柄
DWORD dwFlags, // 选项
LPCVOID lpMem // 内存指针
);
|
GetProcessHeap - 获取进程默认堆
示例:
| C++ |
|---|
| HANDLE hDefaultHeap = GetProcessHeap();
LPVOID pMem = HeapAlloc(hDefaultHeap, 0, 1024);
|
完整示例
| C++ |
|---|
| #include <windows.h>
#include <stdio.h>
int main() {
// 创建堆
HANDLE hHeap = HeapCreate(0, 1024 * 1024, 0);
if (hHeap == NULL) {
printf("HeapCreate failed\n");
return -1;
}
// 分配内存
LPVOID pBuffer = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, 1024);
if (pBuffer == NULL) {
printf("HeapAlloc failed\n");
HeapDestroy(hHeap);
return -1;
}
// 使用内存
strcpy((char*)pBuffer, "Hello, Heap!");
printf("%s\n", (char*)pBuffer);
// 获取分配大小
SIZE_T size = HeapSize(hHeap, 0, pBuffer);
printf("Allocated size: %zu bytes\n", size);
// 重分配
pBuffer = HeapReAlloc(hHeap, HEAP_ZERO_MEMORY, pBuffer, 2048);
if (pBuffer) {
printf("Reallocated to 2048 bytes\n");
}
// 释放内存
HeapFree(hHeap, 0, pBuffer);
// 销毁堆
HeapDestroy(hHeap);
return 0;
}
|
虚拟内存管理
VirtualAlloc - 分配虚拟内存
| C++ |
|---|
| LPVOID VirtualAlloc(
LPVOID lpAddress, // 期望的分配地址
SIZE_T dwSize, // 分配大小
DWORD flAllocationType, // 分配类型
DWORD flProtect // 内存保护属性
);
|
分配类型:
- MEM_COMMIT:提交物理存储
- MEM_RESERVE:保留地址空间
- MEM_RESET:重置内存区域
- MEM_TOP_DOWN:从高地址分配
保护属性:
- PAGE_NOACCESS:不可访问
- PAGE_READONLY:只读
- PAGE_READWRITE:读写
- PAGE_EXECUTE:可执行
- PAGE_EXECUTE_READ:可执行和读取
- PAGE_EXECUTE_READWRITE:可执行、读取和写入
示例:
| C++ |
|---|
| // 保留并提交10MB内存
LPVOID pMem = VirtualAlloc(
NULL, // 系统决定地址
10 * 1024 * 1024, // 10MB
MEM_RESERVE | MEM_COMMIT, // 保留并提交
PAGE_READWRITE // 读写权限
);
if (pMem == NULL) {
printf("VirtualAlloc failed: %d\n", GetLastError());
}
|
VirtualFree - 释放虚拟内存
| C++ |
|---|
| BOOL VirtualFree(
LPVOID lpAddress, // 地址
SIZE_T dwSize, // 大小
DWORD dwFreeType // 释放类型
);
|
释放类型:
- MEM_DECOMMIT:取消提交
- MEM_RELEASE:释放区域(dwSize必须为0)
示例:
| C++ |
|---|
| VirtualFree(pMem, 0, MEM_RELEASE); // 完全释放
|
VirtualProtect - 修改内存保护属性
| C++ |
|---|
| BOOL VirtualProtect(
LPVOID lpAddress, // 地址
SIZE_T dwSize, // 大小
DWORD flNewProtect, // 新保护属性
PDWORD lpflOldProtect // 旧保护属性
);
|
示例:
| C++ |
|---|
| DWORD dwOldProtect;
VirtualProtect(pMem, 4096, PAGE_READONLY, &dwOldProtect); // 改为只读
|
VirtualQuery - 查询内存信息
| C++ |
|---|
| SIZE_T VirtualQuery(
LPCVOID lpAddress,
PMEMORY_BASIC_INFORMATION lpBuffer,
SIZE_T dwLength
);
|
MEMORY_BASIC_INFORMATION结构:
| C++ |
|---|
| typedef struct _MEMORY_BASIC_INFORMATION {
PVOID BaseAddress; // 区域基地址
PVOID AllocationBase; // 分配基地址
DWORD AllocationProtect; // 初始保护属性
SIZE_T RegionSize; // 区域大小
DWORD State; // 状态(MEM_COMMIT/MEM_RESERVE/MEM_FREE)
DWORD Protect; // 当前保护属性
DWORD Type; // 类型(MEM_PRIVATE/MEM_MAPPED/MEM_IMAGE)
} MEMORY_BASIC_INFORMATION;
|
完整示例
| C++ |
|---|
| #include <windows.h>
#include <stdio.h>
int main() {
// 分配虚拟内存
SIZE_T size = 4 * 1024 * 1024; // 4MB
LPVOID pMem = VirtualAlloc(
NULL,
size,
MEM_RESERVE | MEM_COMMIT,
PAGE_READWRITE
);
if (pMem == NULL) {
printf("VirtualAlloc failed: %d\n", GetLastError());
return -1;
}
printf("Allocated at: %p\n", pMem);
// 使用内存
memset(pMem, 0xAA, size);
// 查询内存信息
MEMORY_BASIC_INFORMATION mbi;
VirtualQuery(pMem, &mbi, sizeof(mbi));
printf("Region size: %zu bytes\n", mbi.RegionSize);
// 修改保护属性为只读
DWORD dwOldProtect;
VirtualProtect(pMem, size, PAGE_READONLY, &dwOldProtect);
printf("Changed to read-only\n");
// 释放内存
VirtualFree(pMem, 0, MEM_RELEASE);
printf("Memory released\n");
return 0;
}
|
内存映射文件
CreateFileMapping - 创建文件映射对象
| C++ |
|---|
| HANDLE CreateFileMapping(
HANDLE hFile, // 文件句柄
LPSECURITY_ATTRIBUTES lpAttributes, // 安全属性
DWORD flProtect, // 保护属性
DWORD dwMaximumSizeHigh, // 最大大小高32位
DWORD dwMaximumSizeLow, // 最大大小低32位
LPCTSTR lpName // 对象名称
);
|
参数:
- hFile:文件句柄(INVALID_HANDLE_VALUE表示创建分页文件支持的映射)
- flProtect:
- PAGE_READONLY
- PAGE_READWRITE
- PAGE_WRITECOPY
- PAGE_EXECUTE_READ
- PAGE_EXECUTE_READWRITE
示例:
| C++ |
|---|
| // 创建文件映射(使用分页文件)
HANDLE hMap = CreateFileMapping(
INVALID_HANDLE_VALUE, // 使用分页文件
NULL,
PAGE_READWRITE,
0,
1024 * 1024, // 1MB
L"MySharedMemory"
);
if (hMap == NULL) {
printf("CreateFileMapping failed: %d\n", GetLastError());
}
|
OpenFileMapping - 打开现有文件映射
| C++ |
|---|
| HANDLE OpenFileMapping(
DWORD dwDesiredAccess, // 访问权限
BOOL bInheritHandle, // 继承标志
LPCTSTR lpName // 对象名称
);
|
MapViewOfFile - 映射视图
| C++ |
|---|
| LPVOID MapViewOfFile(
HANDLE hFileMappingObject, // 文件映射对象
DWORD dwDesiredAccess, // 访问权限
DWORD dwFileOffsetHigh, // 偏移高32位
DWORD dwFileOffsetLow, // 偏移低32位
SIZE_T dwNumberOfBytesToMap // 映射字节数
);
|
访问权限:
- FILE_MAP_READ
- FILE_MAP_WRITE
- FILE_MAP_ALL_ACCESS
- FILE_MAP_COPY
示例:
| C++ |
|---|
| LPVOID pData = MapViewOfFile(
hMap,
FILE_MAP_ALL_ACCESS,
0, 0, 0 // 映射整个文件
);
if (pData == NULL) {
printf("MapViewOfFile failed: %d\n", GetLastError());
}
|
UnmapViewOfFile - 取消映射视图
| C++ |
|---|
| BOOL UnmapViewOfFile(
LPCVOID lpBaseAddress // 基地址
);
|
FlushViewOfFile - 刷新视图到文件
| C++ |
|---|
| BOOL FlushViewOfFile(
LPCVOID lpBaseAddress, // 基地址
SIZE_T dwNumberOfBytesToFlush // 字节数
);
|
完整示例 - 共享内存
| C++ |
|---|
| // 进程1:创建共享内存
#include <windows.h>
#include <stdio.h>
int main() {
// 创建文件映射
HANDLE hMap = CreateFileMapping(
INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
0,
1024,
L"SharedMemory"
);
if (hMap == NULL || GetLastError() == ERROR_ALREADY_EXISTS) {
printf("CreateFileMapping failed\n");
return -1;
}
// 映射视图
LPSTR pData = (LPSTR)MapViewOfFile(
hMap,
FILE_MAP_ALL_ACCESS,
0, 0, 0
);
// 写入数据
strcpy(pData, "Hello from Process 1!");
printf("Written: %s\n", pData);
// 等待用户按键
getchar();
// 清理
UnmapViewOfFile(pData);
CloseHandle(hMap);
return 0;
}
|
| C++ |
|---|
| // 进程2:访问共享内存
#include <windows.h>
#include <stdio.h>
int main() {
// 打开文件映射
HANDLE hMap = OpenFileMapping(
FILE_MAP_ALL_ACCESS,
FALSE,
L"SharedMemory"
);
if (hMap == NULL) {
printf("OpenFileMapping failed: %d\n", GetLastError());
return -1;
}
// 映射视图
LPSTR pData = (LPSTR)MapViewOfFile(
hMap,
FILE_MAP_ALL_ACCESS,
0, 0, 0
);
// 读取数据
printf("Read: %s\n", pData);
// 清理
UnmapViewOfFile(pData);
CloseHandle(hMap);
return 0;
}
|
其他内存函数
GlobalAlloc/LocalAlloc
已废弃
这些函数是16位Windows遗留,现代应用应使用HeapAlloc。
| C++ |
|---|
| HGLOBAL GlobalAlloc(UINT uFlags, SIZE_T dwBytes);
HGLOBAL GlobalReAlloc(HGLOBAL hMem, SIZE_T dwBytes, UINT uFlags);
LPVOID GlobalLock(HGLOBAL hMem);
BOOL GlobalUnlock(HGLOBAL hMem);
SIZE_T GlobalSize(HGLOBAL hMem);
HGLOBAL GlobalFree(HGLOBAL hMem);
|
RtlMoveMemory/RtlCopyMemory
| C++ |
|---|
| void RtlMoveMemory(void* Destination, const void* Source, size_t Length);
void RtlCopyMemory(void* Destination, const void* Source, size_t Length);
void RtlZeroMemory(void* Destination, size_t Length);
void RtlFillMemory(void* Destination, size_t Length, BYTE Fill);
|
ZeroMemory/FillMemory
| C++ |
|---|
| #define ZeroMemory(Destination, Length) memset((Destination), 0, (Length))
#define FillMemory(Destination, Length, Fill) memset((Destination), (Fill), (Length))
|
内存状态查询
GlobalMemoryStatusEx
| C++ |
|---|
| BOOL GlobalMemoryStatusEx(
LPMEMORYSTATUSEX lpBuffer
);
|
MEMORYSTATUSEX结构:
| C++ |
|---|
| typedef struct _MEMORYSTATUSEX {
DWORD dwLength; // 结构大小
DWORD dwMemoryLoad; // 内存使用百分比
DWORDLONG ullTotalPhys; // 物理内存总量
DWORDLONG ullAvailPhys; // 可用物理内存
DWORDLONG ullTotalPageFile; // 页面文件总量
DWORDLONG ullAvailPageFile; // 可用页面文件
DWORDLONG ullTotalVirtual; // 虚拟内存总量
DWORDLONG ullAvailVirtual; // 可用虚拟内存
DWORDLONG ullAvailExtendedVirtual; // 可用扩展虚拟内存
} MEMORYSTATUSEX;
|
示例:
| C++ |
|---|
| MEMORYSTATUSEX statex;
statex.dwLength = sizeof(statex);
GlobalMemoryStatusEx(&statex);
printf("Memory load: %d%%\n", statex.dwMemoryLoad);
printf("Total physical memory: %llu MB\n", statex.ullTotalPhys / (1024 * 1024));
printf("Available physical memory: %llu MB\n", statex.ullAvailPhys / (1024 * 1024));
|
参考资料