Linux下读取/proc/self/status的VmRSS字段(单位KB)最轻量常用,反映真实物理内存占用;Windows用GetProcessMemoryInfo获取WorkingSetSize,二者等价;避免使用mallinfo等堆内指标,因其严重低估真实内存。

Linux 下用 /proc/self/status 读取当前进程 RSS 内存
最轻量、最常用的方法是读取 /proc/self/status 文件中的 VmRSS 字段,它代表当前进程实际占用的物理内存(单位:KB)。这个值不包含 swap,也不含共享内存重复计算,适合监控真实内存压力。
注意:/proc 是 Linux 特有接口,Windows 不可用;且需确保程序有读取该文件权限(通常都有)。
-
VmRSS值会滞后于 malloc/free 调用,因为内核按页回收,不是立即释放 - 不要解析
VmSize(虚拟内存大小),它包含未分配的 mmap 区域和保留地址空间,不能反映真实内存压力 - 建议每秒读取不超过 10 次,频繁读
/proc/self/status会产生轻微 I/O 开销
FILE* f = fopen("/proc/self/status", "r");
if (f) {
char line[256];
while (fgets(line, sizeof(line), f)) {
if (strncmp(line, "VmRSS:", 6) == 0) {
long rss_kb;
sscanf(line, "VmRSS: %ld kB", &rss_kb);
printf("RSS: %ld KB\n", rss_kb);
break;
}
}
fclose(f);
}Windows 下用 GetProcessMemoryInfo 获取工作集大小
Windows 对应方案是调用 psapi.h 中的 GetProcessMemoryInfo,读取 PROCESS_MEMORY_COUNTERS::WorkingSetSize。它等价于 Linux 的 VmRSS,即当前驻留在物理内存中的字节数。
需要链接 psapi.lib,并在项目中定义 PSAPI_VERSION 1(否则可能返回 0)。
立即学习“C++免费学习笔记(深入)”;
-
WorkingSetSize包含私有内存 + 共享内存(如系统 DLL),但不含已换出页面 - 如果函数返回
FALSE,检查是否漏加#pragma comment(lib, "psapi.lib")或未启用PSAPI_VERSION - 避免在多线程高频调用中反复打开/关闭当前进程句柄;复用
GetCurrentProcess()返回的句柄即可
#include#include #pragma comment(lib, "psapi.lib") void print_memory_usage() { PROCESS_MEMORY_COUNTERS pmc; if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) { printf("WorkingSetSize: %zu KB\n", pmc.WorkingSetSize / 1024); } }
跨平台封装时慎用 mallinfo 和 malloc_stats
mallinfo(glibc)和 malloc_stats 输出的是堆管理器内部视图,不是 OS 看到的真实内存。它们只统计 malloc 系统调用分配的 heap 区域,忽略 mmap 分配的大块内存(如 std::vector 超过阈值后自动切到 mmap)、静态数据、栈、共享库等。
因此,这些接口容易严重低估真实内存占用,尤其在大量使用 std::string、std::vector 或第三方库(如 protobuf、OpenCV)时。
-
mallinfo().uordblks只反映 glibc malloc arena 中已分配但未 free 的字节数 -
malloc_stats()输出到 stderr,无法直接捕获,且格式不固定,不适合自动化解析 - C++17 起,
std::allocator不保证调用malloc,部分实现走mmap,mallinfo完全不可见
监控精度与采样频率的实际取舍
内存监控不是越细越好。高频采样(如每毫秒)本身就会增加调度开销和锁竞争(尤其是 /proc 文件读取或 Windows PSAPI 调用),反而干扰被测程序行为。
真实场景下,推荐按需分层:
- 调试阶段:每 100–500ms 采样一次,配合关键路径打点(如函数入口/出口)
- 线上服务:每 5–30 秒聚合一次,写入日志或上报 metrics,避免 IO 毛刺
- OOM 分析:配合
setrlimit(RLIMIT_AS)或 cgroup memory.max(Linux)做硬限制,比事后查 RSS 更可靠
真正难的不是“怎么读内存”,而是判断哪个值能对应你关心的问题——是防止 OOM?定位泄漏?还是优化缓存命中率?选错指标,数据再准也没用。










