GetProcessMemoryInfo 获取的是当前进程的 Working Set 大小(即驻留在物理内存中的页数),需链接 psapi.lib 并使用 PROCESS_MEMORY_COUNTERS.WorkingSetSize 字段,其值受系统内存调度影响而波动,并非私有工作集。

Windows 下用 GetProcessMemoryInfo 获取物理内存占用(Working Set)
直接调用 GetProcessMemoryInfo 是 Windows 平台最常用、开销最低的方式,但它返回的是当前进程的 Working Set 大小——即驻留在物理内存中的页数,不是虚拟内存或私有工作集(Private Working Set),这点容易误解。
关键点:
-
GetProcessMemoryInfo需要psapi.lib链接,且运行时依赖psapi.dll(WinXP+ 都有,但 Server 2003 默认不加载,需显式LoadLibrary或确保链接正确) - 必须传入当前进程的句柄,
GetCurrentProcess()返回的是伪句柄,需用DuplicateHandle或直接传给函数(它内部可接受伪句柄) - 结构体
PROCESS_MEMORY_COUNTERS的WorkingSetSize字段才是物理内存占用字节数,别误用PagefileUsage(那是提交量)或PeakWorkingSetSize(历史峰值)
#include <windows.h>
#include <psapi.h>
#pragma comment(lib, "psapi.lib")
SIZE_T GetWorkingSetBytes() {
PROCESS_MEMORY_COUNTERS pmc;
if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) {
return pmc.WorkingSetSize;
}
return 0;
}
</psapi.h></windows.h>
为什么 WorkingSetSize 突然变小?和内存压缩/WS trimming 有关
Windows 会主动回收空闲进程的 Working Set,尤其在内存压力大、或进程长时间挂起时。这不是 bug,是系统行为。你连续两次调用 GetProcessMemoryInfo 得到的值可能相差很大,不代表泄漏或释放,只是 OS 在调度物理页。
常见干扰场景:
- 进程刚启动后立刻查,值偏小(页面还没触发分配)
- 调用
SetProcessWorkingSetSize(GetCurrentProcess(), -1, -1)强制清空 Working Set(调试可用,但线上慎用) - 启用 Memory Compression(Win10 1709+ 默认开启)时,
WorkingSetSize不包含被压缩页,实际物理占用比该值更低
想看私有物理内存(Private Working Set)?得用 QueryWorkingSetEx + 手动过滤
GetProcessMemoryInfo 拿不到 Private Working Set(即真正独占、不可共享的物理内存),这个指标对排查内存泄漏更关键。Windows 提供了 QueryWorkingSetEx,但它是逐页查询,开销大,且需自己遍历所有页并检查 WS_EX_INFORMATION::Shared 标志位。
实操建议:
- 仅在诊断阶段使用,不要高频轮询
- 必须先用
VirtualQueryEx获取内存区域范围,再对每个MEM_COMMIT区域调用QueryWorkingSetEx - 注意:需要
SE_DEBUG_NAME权限才能查其他进程;查自己进程也建议提前调用OpenProcess(PROCESS_QUERY_INFORMATION, ...)而非直接用伪句柄
跨平台方案不存在,Linux/macOS 完全不同机制
别试图封装一个“跨平台”的物理内存获取函数——Linux 用 /proc/self/statm 或 getrusage(RUSAGE_SELF, ...),macOS 用 task_info(TASK_BASIC_INFO),三者语义不等价,返回值单位、是否含共享页、是否实时都不同。
如果真要多平台支持:
- Windows:坚持用
GetProcessMemoryInfo+WorkingSetSize - Linux:读
/proc/self/statm第二列(resident,单位是页),或解析/proc/self/status中的RSS - macOS:调用
task_info取phys_footprint(iOS/macOS 10.9+ 支持,才是真实物理占用)
最后提醒一句:Working Set 是瞬时快照,受系统调度强影响;真要定位内存问题,得结合堆分配追踪(如 _CrtSetDbgFlag、AddressSanitizer)或 ETW/PerfView 采集完整内存生命周期事件。单纯看一个数字,很容易误判。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











