Windows下用GetProcessMemoryInfo获取WorkingSetSize最接近用户感知的内存占用,Linux下读/proc/self/statm第二列resident乘以页大小得RSS;二者均反映实际物理内存使用,是判断内存压力的可靠指标。

Windows下用GetProcessMemoryInfo查当前进程内存占用
直接调用psapi.h里的GetProcessMemoryInfo是最稳妥的方式,它返回的是PROCESS_MEMORY_COUNTERS结构体,其中WorkingSetSize(工作集)最接近用户感知的“已用内存”,PagefileUsage则反映实际提交到页文件的总量。
注意两点:一是必须链接psapi.lib,否则链接报错unresolved external symbol GetProcessMemoryInfo;二是GetProcessMemoryInfo在WinXP之后才稳定支持,旧系统需加#ifdef _WIN32_WINNT判断。
示例关键片段:
#include <windows.h>
#include <psapi.h>
#pragma comment(lib, "psapi.lib")
<p>SIZE_T get_working_set() {
PROCESS_MEMORY_COUNTERS pmc;
if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) {
return pmc.WorkingSetSize;
}
return 0;
}常见误用:有人拿VirtualAlloc分配量减去VirtualFree释放量来估算,这完全不可靠——虚拟地址空间和物理内存占用毫无对应关系。
立即学习“C++免费学习笔记(深入)”;
Linux下读/proc/self/statm或/proc/self/status
/proc/self/statm是最快捷的途径,一行六列,第二列(resident)即常驻物理内存页数,乘以getpagesize()就是字节数。它不触发系统调用,开销极低,适合高频采样。
但要注意:statm的单位是页,不是字节;且该值包含共享库的物理页,若进程大量使用共享内存或动态库,resident会偏高——这不是泄漏,只是统计口径问题。
更准确但稍重的方式是解析/proc/self/status里的RSS(VmRSS字段),它和statm第二列等价,但可读性更好;若需区分堆/栈/共享库用量,得看MMU映射(/proc/self/maps),那已超出“获取使用量”的原始需求。
示例关键片段:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
<p>size_t get_rss_kb() {
FILE<em> f = fopen("/proc/self/statm", "r");
if (!f) return 0;
unsigned long size, resident;
fscanf(f, "%lu %lu", &size, &resident);
fclose(f);
return resident </em> getpagesize() / 1024; // KB
}跨平台封装时别碰mallinfo和malloc_stats
mallinfo在glibc 2.33+已被标记为废弃,返回值语义模糊(比如uordblks只计malloc系分配、不含mmap大块),且Windows根本不存在;malloc_stats只是打印到stderr,无法取值,纯调试用途。
真正跨平台的底线做法是:Windows走GetProcessMemoryInfo,Linux走/proc/self/statm,用宏或CMake条件编译隔离。强行统一接口只会引入隐性偏差——例如把Linux的VmSize(虚拟地址空间)当内存用量,可能比实际高十倍。
容易忽略的细节:
-
WorkingSetSize在Windows上受系统内存压力影响剧烈,空闲时可能被压缩,不代表真实堆用量 -
/proc/self/statm第一列(size)是总虚拟内存页数,不是“已分配”——它包含未访问的mmap区域,也包含保留但未提交的地址空间 - 多线程程序中,这些API返回的是整个进程视图,无法定位到某次
new或malloc的具体开销
调试内存增长时优先看WorkingSetSize或RSS,而非HeapSize
很多开发者一上来就调GetProcessHeaps + HeapWalk(Windows)或malloc_usable_size(Linux),结果发现数字远小于任务管理器显示值。这是因为堆管理器只管HeapAlloc或malloc路径,而C++里new可能走VirtualAlloc(大对象)、mmap(Linux默认分配器对>128KB走mmap)、甚至DirectX/OpenGL显存映射——这些全算在WorkingSetSize或RSS里,但不在堆统计中。
所以,如果观察到内存持续上涨但堆遍历没变化,重点检查:std::vector::reserve是否过度预分配、第三方库是否用了私有内存池、是否频繁创建std::thread(每个线程栈默认1MB)。
一句话收尾:真实内存压力永远体现在WorkingSetSize(Windows)或RSS(Linux)上,其余指标只是子集,别让它们干扰对整体水位的判断。


















