linux下/proc/self/status中的vmrss和vmsize反映进程整体物理/虚拟内存占用,与malloc实际分配量无一一对应关系;因glibc ptmalloc缓存复用机制,free后内存未必归还内核,需通过ld_preload拦截或malloc_stats等手段间接估算堆行为。

Linux下用/proc/self/status读取进程堆内存总量(RSS/VSZ)但不等于malloc分配量
直接看/proc/self/status里的VmRSS或VmSize,得到的是整个进程的物理/虚拟内存占用,包含代码段、栈、共享库、mmap映射等,**和malloc实际申请的堆内存无一一对应关系**。比如你调用malloc(1MB)后立刻free,VmRSS很可能不变——glibc的ptmalloc会把小块内存留在arena里复用,不急着还给内核。
想统计malloc/free行为?必须自己拦截或启用glibc malloc调试
标准C++不提供运行时堆分配明细API。可行路径只有两条:
- 用
LD_PRELOAD劫持malloc、free、realloc,在自己的wrapper里累加计数器(注意线程安全,需用__atomic_fetch_add或std::atomic) - 启用glibc内置的
mallinfo或malloc_stats——但它们只反映当前malloc管理器状态,不记录历史释放量,且mallinfo在glibc 2.33+已被标记为废弃
示例:启用malloc_stats输出到stderr(无返回值,纯打印):
export MALLOC_TRACE=/dev/stderr ./your_program或在代码里调用
malloc_stats(),它会打印类似Arena 0: system bytes = 135168的信息,其中system bytes是向内核申请的总大小,in use bytes是当前被用户持有的大小,差值近似“已分配但未释放”的量——但不是“已释放量”,而是“尚未归还给内核的脏页”。Windows下没有等效/proc,得靠HeapWalk或CRT调试堆
Windows原生堆API(HeapCreate + HeapWalk)只能遍历当前堆块状态,无法区分“曾分配过但已释放”的历史;CRT调试堆(_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF))可记录每次malloc位置,但只对_malloc_dbg生效,且默认不统计总量。真正能拿到累计分配/释放字节数的,只有VC++的_CrtMemState快照对比:
_CrtMemState s1, s2, diff;
_CrtMemCheckpoint(&s1);
// ... your code ...
_CrtMemCheckpoint(&s2);
if (_CrtMemDifference(&diff, &s1, &s2)) {
printf("allocated - freed = %zu bytes\n", diff.lSizes[0]);
}
注意:diff.lSizes[0]是当前净增量,不是“已释放量”。要算释放量,得两次快照之间手动记下分配总量,再推导——没有现成字段存“总共free过多少次字节”。
别指望std::allocator或new操作符重载自动帮你统计全局堆
重载operator new和operator delete确实能捕获C++层分配,但绕不过malloc被第三方库(如libpng、openssl)直接调用的情况;而且std::vector内部可能用malloc而非new(取决于实现),std::string小字符串优化(SSO)甚至根本不走堆。所以仅靠重载new会严重低估真实堆活动量。
真正可靠的方案只有一个:从malloc入口拦截,并接受“已释放量”本质上是个模糊概念——因为glibc不会告诉你某次free是否真的触发了brk或madvise(MADV_DONTNEED),它只管自己arena的管理逻辑。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











