Linux 用 /proc/self/status 的 VmHWM 字段(KB)获取 RSS 峰值内存,Windows 用 GetProcessMemoryInfo 的 PeakWorkingSetSize(字节转 KB),二者均需在进程退出前通过 atexit 安全读取,避免使用 mallinfo 或 malloc_stats 等不完整方案。

Linux 下用 /proc/self/status 读取峰值内存(VmHWM)
Linux 内核在进程运行时会持续更新 /proc/self/status,其中 VmHWM 字段(High Water Mark)记录了该进程自启动以来使用的最大物理内存(单位:KB)。这是最轻量、最准确的峰值内存获取方式,无需额外依赖或侵入式 hook。
注意:VmHWM 是 RSS 峰值(常驻集大小),不包含 swap 或未映射页,但对绝大多数 C++ 应用已足够反映真实内存压力。
实操建议:
- 在程序**退出前**(比如
main()结尾或atexit回调中)读取,避免提前被其他线程/子进程干扰 - 用
std::ifstream逐行扫描,匹配以“VmHWM:”开头的行,再提取数字部分(注意空格和制表符) - 不要依赖
VmPeak—— 它是虚拟地址空间峰值,可能远大于实际物理内存占用,且受mmap、大页等影响失真
long get_peak_rss_kb() {
std::ifstream f("/proc/self/status");
std::string line;
while (std::getline(f, line)) {
if (line.rfind("VmHWM:", 0) == 0) {
return std::stol(line.substr(6));
}
}
return 0;
}
Windows 下用 GetProcessMemoryInfo 获取 PeakWorkingSetSize
Windows 没有直接等价于 VmHWM 的接口,但 GetProcessMemoryInfo 返回的 PROCESS_MEMORY_COUNTERS 结构体中,PeakWorkingSetSize 字段(单位:字节)最接近 Linux 的 VmHWM,表示进程工作集大小的历史最大值。
立即学习“C++免费学习笔记(深入)”;
关键限制:
- 该值仅在进程处于用户态且未被系统回收页时更新,若程序长时间休眠后唤醒,可能滞后
- 必须链接
psapi.lib,并在编译时定义PSAPI_VERSION=1(否则默认用旧版结构体,无PeakWorkingSetSize) - 返回值为字节,需手动除以 1024 转成 KB 以便与 Linux 结果对齐
#include <psapi.h>
#pragma comment(lib, "psapi.lib")
size_t get_peak_working_set_kb() {
PROCESS_MEMORY_COUNTERS pmc;
if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) {
return pmc.PeakWorkingSetSize / 1024;
}
return 0;
}
跨平台封装时避开 mallinfo 和 malloc_stats
别用 mallinfo(glibc)或 malloc_stats:它们只统计 malloc 系统分配器管理的堆内存,完全忽略 mmap 分配的大块内存(如 std::vector 超过阈值后的扩容)、静态数据、栈空间、共享库加载开销——而这些恰恰是现代 C++ 程序内存峰值的主要来源。
更糟的是:mallinfo 在 glibc 2.33+ 已被标记为废弃,musl libc 根本不提供;malloc_stats 输出到 stderr,无法直接捕获,且格式不稳定。
替代思路:
- Linux 严格走
/proc/self/status+VmHWM - Windows 严格走
GetProcessMemoryInfo+PeakWorkingSetSize - macOS 需用
task_info(TASK_BASIC_INFO或TASK_EVENTS_INFO),但字段语义略有差异,phys_footprint更接近 RSS,需单独处理
输出时机不对会导致读数为 0 或严重偏低
常见错误是把内存读取逻辑放在 main() 中间、或在子线程里调用——此时进程可能还没达到峰值,或者主线程已结束但子线程仍在运行(/proc/self 已失效)。
可靠做法:
- 用
std::atexit注册回调函数,确保在所有全局对象析构之后、进程真正退出前执行 - 避免在信号处理函数(如
SIGINT)中读取——信号中断时内核状态可能不一致,VmHWM可能未刷新 - 如果程序 fork 了子进程,父进程的
VmHWM不包含子进程内存;需分别监控,或改用 cgroup v2 +memory.max_usage_in_bytes(需 root 权限)
最后提醒一句:VmHWM 和 PeakWorkingSetSize 都是单次运行的瞬时快照,无法反映多轮迭代下的内存泄漏趋势。真要查泄漏,得结合 ASan 或 Valgrind,而不是只看峰值。


















