c++中如何获取程序运行过程中的内存占用_c++监控内存方法【详解】

9次阅读

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

c++中如何获取程序运行过程中的内存占用_c++监控内存方法【详解】

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 KBn", 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 KBn", pmc.WorkingSetSize / 1024); } }

跨平台封装时慎用 mallinfomalloc_stats

mallinfo(glibc)和 malloc_stats 输出的是堆管理器内部视图,不是 OS 看到的真实内存。它们只统计 malloc 系统调用分配的 heap 区域,忽略 mmap 分配的大块内存(如 std::vector 超过阈值后自动切到 mmap)、静态数据、、共享库等。

因此,这些接口容易严重低估真实内存占用,尤其在大量使用 std::Stringstd::vector 或第三方库(如 protobuf、opencv)时。

  • mallinfo().uordblks 只反映 glibc malloc arena 中已分配但未 free 的字节
  • malloc_stats() 输出到 stderr,无法直接捕获,且格式不固定,不适合自动化解析
  • c++17 起,std::allocator 不保证调用 malloc,部分实现走 mmapmallinfo 完全不可见

监控精度与采样频率的实际取舍

内存监控不是越细越好。高频采样(如每毫秒)本身就会增加调度开销和锁竞争(尤其是 /proc 文件读取或 Windows PSAPI 调用),反而干扰被测程序行为。

真实场景下,推荐按需分层:

  • 调试阶段:每 100–500ms 采样一次,配合关键路径打点(如函数入口/出口)
  • 线上服务:每 5–30 秒聚合一次,写入日志或上报 metrics,避免 IO 毛刺
  • OOM 分析:配合 setrlimit(RLIMIT_AS) 或 cgroup memory.max(Linux)做硬限制,比事后查 RSS 更可靠

真正难的不是“怎么读内存”,而是判断哪个值能对应你关心的问题——是防止 OOM?定位泄漏?还是优化缓存命中率?选错指标,数据再准也没用。

text=ZqhQzanResources