windows下用getprocessmemoryinfo获取workingsetsize(字节)最可靠,linux下读/proc/self/statm第二列乘页大小得rss;二者均反映当前驻留物理内存,但语义不完全等价。

Windows 下用 GetProcessMemoryInfo 读取工作集大小
在 Windows 平台,GetProcessMemoryInfo 是获取当前进程工作集(Working Set)最直接、最可靠的方式。它返回的 WORKING_SET_INFORMATION 结构并不直接暴露,而是通过 PROCESS_MEMORY_COUNTERS 中的 WorkingSetSize 字段提供字节数——这个值就是当前驻留在物理内存中的页总大小(不含已换出页)。
常见错误是误用 PagefileUsage 或 PeakWorkingSetSize:前者含交换文件用量,后者是历史峰值,都不是「当前实时驻留物理内存」的准确反映。
- 需链接
psapi.lib,头文件为<psapi.h></psapi.h> - 调用前确保进程有
PROCESS_QUERY_INFORMATION权限(当前进程默认具备) -
WorkingSetSize单位是字节,不是页数;除以 4096 可得页数(但通常直接用字节更直观)
#include <psapi.h>
#include <iostream><p>size_t GetCurrentWorkingSet() {
PROCESS_MEMORY_COUNTERS pmc;
if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) {
return pmc.WorkingSetSize;
}
return 0;
}
</p></iostream></psapi.h>
Linux 下用 /proc/self/statm 解析工作集近似值
Linux 没有严格等价于 Windows 工作集的 API,/proc/self/statm 的第二列(resident)是最接近的指标:它表示当前映射且驻留在物理内存中的页数(单位是系统页大小,通常是 4096 字节)。
注意:它不区分共享页是否被其他进程引用,也不排除内核标记为“可回收但尚未回收”的页,因此是近似值,但对大多数监控场景足够实用。
- 不能用
getrusage的ru_maxrss:那是峰值常驻集,不可实时更新 - 避免反复 fopen/fclose;建议用
std::ifstream一次性读取并解析,或 mmap + sscanf 提升效率 - 读取时若遇到
ENOENT或权限拒绝(少见),应 fallback 到 0 或记录警告
#include <fstream>
#include <string><p>size_t GetCurrentWorkingSet() {
std::ifstream f("/proc/self/statm");
if (!f.is_open()) return 0;
size_t size, resident;
f >> size >> resident; // 第二列是 resident pages
return resident * sysconf(_SC_PAGESIZE);
}
</p></string></fstream>
跨平台封装要注意的三个关键点
如果写跨平台代码,不要试图抽象出统一语义的“工作集”——Windows 和 Linux 底层机制差异太大,强行统一反而误导使用者。应明确标注每个平台返回值的实际含义。
- Windows 的
WorkingSetSize包含私有页 + 共享页(只要当前进程引用了就计入) - Linux 的
statm第二列也包含共享页,但内核可能因 LRU 策略延迟回收,瞬时值波动更大 - 两者都不包括被锁定(locked)但未映射进进程地址空间的内存(如
mlock后未访问的页)
为什么不用 VirtualQueryEx 或 mincore?
有人想用 VirtualQueryEx 遍历所有内存区域再逐个查 MEM_COMMIT + 物理页状态,或在 Linux 用 mincore 检查每页是否驻留——理论上可行,但实际几乎没人这么做。
- 性能极差:
VirtualQueryEx在大进程上可能触发数千次系统调用;mincore对 GB 级内存要循环调用,且需处理ENOMEM分批 - 精度未必更高:例如
mincore返回的“驻留”标志受最近访问影响,而statm是内核维护的统计快照,更稳定 - 权限与稳定性风险:
VirtualQueryEx跨进程需额外权限;mincore在某些内核版本对匿名映射行为不一致
真实项目里,用 GetProcessMemoryInfo 或 /proc/self/statm 就够了。追求毫秒级精确驻留页分布的场景,本身就不适合靠用户态轮询解决——该上 eBPF 或内核跟踪器。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











