最贴近用户感知的物理内存占用量是Windows用GetProcessMemoryInfo读WorkingSetSize、Linux读/proc/self/status的VmRSS;mallinfo等仅统计堆内存,漏掉mmap分配等,严重低估真实占用。

直接用 GetProcessMemoryInfo 读 WorkingSetSize(Windows)或读 /proc/self/status 中的 VmRSS(Linux),这是最贴近用户感知的物理内存占用量。其他方式如 mallinfo、VirtualAlloc 差值、VmSize 等,要么漏内存,要么算的是虚拟地址空间,不能反映真实 RAM 占用。
Windows:用 GetProcessMemoryInfo 取 WorkingSetSize
它返回当前进程“驻留在物理内存中的字节数”,包含私有页和共享页(如系统 DLL),但不包含已换出页,和任务管理器“内存”列基本一致。
- 必须链接
psapi.lib,否则链接时报unresolved external symbol GetProcessMemoryInfo - 结构体
PROCESS_MEMORY_COUNTERS的cb字段必须设为sizeof(pmc),否则函数返回FALSE - 句柄用
GetCurrentProcess()最安全,无需额外权限 - 不要用
PagefileUsage或PrivateUsage代替——前者含 swap 预留,后者不含共享库,都不等于用户看到的“占了多少内存”
示例片段:
#include <windows.h>
#include <psapi.h>
#pragma comment(lib, "psapi.lib")
<p>size_t get_working_set_bytes() {
PROCESS_MEMORY_COUNTERS pmc = {0};
pmc.cb = sizeof(pmc);
if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) {
return pmc.WorkingSetSize;
}
return 0;
}Linux:解析 /proc/self/status 的 VmRSS 字段
VmRSS 单位是 KB,代表当前进程实际占用的物理内存页(resident set size),和 Windows 的 WorkingSetSize 是同一维度指标。
立即学习“C++免费学习笔记(深入)”;
直播话术巡检系统(Windows版) — 实时语音转写、关键词检测、场景自动切换、告警推送、大屏可视化。支持 Windows VB-Cable 虚拟声卡音频采集,阿里云 ASR 实时识别。一键启动脚本,自动安装环境。
- 必须用
fopen("/proc/self/status", "r"),不用std::ifstream——某些容器或嵌入式环境会禁用 iostream 底层缓冲逻辑,导致读失败 - 逐行
fgets+sscanf匹配"VmRSS: %ld kB",比按字段索引更健壮(内核版本更新不影响) - 别用
/proc/self/statm第二列再乘页大小——它不区分共享/私有,且单位易错;VmRSS已是最终 KB 值,更直观 -
VmRSS有轻微滞后性(内核按页回收),但对监控足够可靠;高频读取(
示例片段:
#include <stdio.h>
#include <stdlib.h>
<p>long get_rss_kb() {
FILE* f = fopen("/proc/self/status", "r");
if (!f) return 0;
char line[256];
long rss = 0;
while (fgets(line, sizeof(line), f)) {
if (sscanf(line, "VmRSS: %ld kB", &rss) == 1) break;
}
fclose(f);
return rss;
}为什么不能用 mallinfo 或 malloc_stats
这两个函数只统计 glibc malloc 堆管理器内部状态,完全看不到 mmap 分配的大块内存(比如 std::vector 超过阈值后自动切到 mmap)、线程栈、静态数据段、共享库代码段。
-
mallinfo返回的uordblks常比真实 RSS 小 30%–70%,尤其在大量使用std::string、std::shared_ptr缓冲区时 -
malloc_stats输出到stderr,格式无保证(glibc 版本一变字段顺序就崩),无法稳定提取数值 - C++ 运行时底层可能绕过 malloc 直接调用
mmap(例如分配 >128KB 时),mallinfo对这部分内存完全失明
跨平台封装时最关键的细节
别写成简单 #ifdef _WIN32 两套分支就完事。真实项目里容易栽在三个地方:
- Linux 上若内核 /proc/self/status 没有
MemAvailable:字段,但你的进程内存监控代码不需要这个——你查的是自己进程的VmRSS,不是系统总内存,所以完全不受影响 - Windows 下 32 位程序调用
GlobalMemoryStatusEx时,ullTotalPhys等字段仍能正确返回 64 位值,但某些旧编译器对ULONGLONG支持不稳,建议统一用uint64_t接收 - 频繁调用时,别在每次函数入口都
fopen/fclose或反复调用GetCurrentProcess()——文件描述符和进程句柄可复用,减少系统调用开销
真正难的不是读哪个字段,而是理解:物理内存占用是个瞬时快照,受共享页、缓存策略、换页行为影响,没有绝对“精确”的值;WorkingSetSize 和 VmRSS 是操作系统公开提供的、最贴近用户直觉的指标,其余都是自欺欺人。


















