跳转至

内存管理API

概述

Windows提供了多种内存管理机制,包括堆内存、虚拟内存和内存映射文件等。不同的内存管理方式适用于不同的场景。

内存管理方式

  • 堆内存(Heap):最常用,适合小粒度内存分配
  • 虚拟内存(Virtual):底层操作,适合大块内存管理
  • 内存映射文件(File Mapping):文件与内存映射,进程间共享
  • 全局/局部内存:16位Windows遗留,已不推荐使用

堆内存管理

HeapCreate - 创建堆

C++
1
2
3
4
5
HANDLE HeapCreate(
    DWORD flOptions,      // 堆分配选项
    SIZE_T dwInitialSize, // 初始大小(字节)
    SIZE_T dwMaximumSize  // 最大大小(字节)
);

参数: - flOptions: - 0:默认 - HEAP_GENERATE_EXCEPTIONS:分配失败时抛出异常 - HEAP_NO_SERIALIZE:不序列化访问 - dwInitialSize:初始提交大小 - dwMaximumSize:最大大小(0表示可增长)

返回值:成功返回堆句柄,失败返回NULL

示例

C++
1
2
3
4
5
HANDLE hHeap = HeapCreate(0, 1024 * 1024, 0);  // 创建1MB初始大小的堆
if (hHeap == NULL) {
    printf("HeapCreate failed: %d\n", GetLastError());
    return -1;
}

HeapAlloc - 分配堆内存

C++
1
2
3
4
5
LPVOID HeapAlloc(
    HANDLE hHeap,   // 堆句柄
    DWORD  dwFlags, // 分配选项
    SIZE_T dwBytes  // 分配字节数
);

参数: - dwFlags: - 0:默认 - HEAP_GENERATE_EXCEPTIONS:失败时抛出异常 - HEAP_NO_SERIALIZE:不序列化 - HEAP_ZERO_MEMORY:初始化为零

示例

C++
1
2
3
4
5
6
7
// 分配内存
LPVOID pMem = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, 1024);
if (pMem == NULL) {
    printf("HeapAlloc failed: %d\n", GetLastError());
    HeapDestroy(hHeap);
    return -1;
}

HeapReAlloc - 重分配堆内存

C++
1
2
3
4
5
6
LPVOID HeapReAlloc(
    HANDLE hHeap,      // 堆句柄
    DWORD  dwFlags,    // 分配选项
    LPVOID lpMem,      // 原内存指针
    SIZE_T dwBytes     // 新大小
);

示例

C++
1
2
3
4
5
// 扩展内存到2048字节
LPVOID pNewMem = HeapReAlloc(hHeap, HEAP_ZERO_MEMORY, pMem, 2048);
if (pNewMem == NULL) {
    printf("HeapReAlloc failed: %d\n", GetLastError());
}

HeapFree - 释放堆内存

C++
1
2
3
4
5
BOOL HeapFree(
    HANDLE hHeap,   // 堆句柄
    DWORD  dwFlags, // 释放选项
    LPVOID lpMem    // 内存指针
);

示例

C++
HeapFree(hHeap, 0, pMem);  // 释放内存

HeapDestroy - 销毁堆

C++
1
2
3
BOOL HeapDestroy(
    HANDLE hHeap  // 堆句柄
);

示例

C++
HeapDestroy(hHeap);  // 销毁堆

HeapSize - 获取分配大小

C++
1
2
3
4
5
SIZE_T HeapSize(
    HANDLE hHeap,   // 堆句柄
    DWORD  dwFlags, // 选项
    LPCVOID lpMem   // 内存指针
);

GetProcessHeap - 获取进程默认堆

C++
HANDLE 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++
1
2
3
4
5
6
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++
1
2
3
4
5
BOOL VirtualFree(
    LPVOID lpAddress,     // 地址
    SIZE_T dwSize,        // 大小
    DWORD  dwFreeType     // 释放类型
);

释放类型: - MEM_DECOMMIT:取消提交 - MEM_RELEASE:释放区域(dwSize必须为0)

示例

C++
VirtualFree(pMem, 0, MEM_RELEASE);  // 完全释放

VirtualProtect - 修改内存保护属性

C++
1
2
3
4
5
6
BOOL VirtualProtect(
    LPVOID lpAddress,         // 地址
    SIZE_T dwSize,            // 大小
    DWORD  flNewProtect,      // 新保护属性
    PDWORD lpflOldProtect     // 旧保护属性
);

示例

C++
DWORD dwOldProtect;
VirtualProtect(pMem, 4096, PAGE_READONLY, &dwOldProtect);  // 改为只读

VirtualQuery - 查询内存信息

C++
1
2
3
4
5
SIZE_T VirtualQuery(
    LPCVOID                   lpAddress,
    PMEMORY_BASIC_INFORMATION lpBuffer,
    SIZE_T                    dwLength
);

MEMORY_BASIC_INFORMATION结构

C++
1
2
3
4
5
6
7
8
9
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++
1
2
3
4
5
6
7
8
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++
1
2
3
4
5
HANDLE OpenFileMapping(
    DWORD   dwDesiredAccess, // 访问权限
    BOOL    bInheritHandle,  // 继承标志
    LPCTSTR lpName           // 对象名称
);

MapViewOfFile - 映射视图

C++
1
2
3
4
5
6
7
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++
1
2
3
4
5
6
7
8
9
LPVOID pData = MapViewOfFile(
    hMap,
    FILE_MAP_ALL_ACCESS,
    0, 0, 0  // 映射整个文件
);

if (pData == NULL) {
    printf("MapViewOfFile failed: %d\n", GetLastError());
}

UnmapViewOfFile - 取消映射视图

C++
1
2
3
BOOL UnmapViewOfFile(
    LPCVOID lpBaseAddress  // 基地址
);

FlushViewOfFile - 刷新视图到文件

C++
1
2
3
4
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++
1
2
3
4
5
6
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++
1
2
3
4
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++
1
2
3
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++
1
2
3
4
5
6
7
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));

参考资料