mallinfo的arena字段近似表示已向系统申请但未释放的堆内存总量,uordblks表示当前已分配且仍在使用的用户块大小;mallinfo已被废弃,推荐malloc_info或/proc/self/status。

Linux下用mallinfo或malloc_stats看堆分配总量
在Linux上,C++程序的堆空间由glibc的malloc管理,mallinfo是最直接获取当前堆使用统计的接口。它返回一个struct mallinfo,其中arena字段(单位字节)近似表示已向系统申请但尚未释放的堆内存总量(即brk段大小),而uordblks表示当前已分配且仍在使用的用户块大小。
注意:mallinfo已被标记为废弃(glibc 2.34+警告),推荐改用malloc_info(输出XML格式)或直接读/proc/self/status更可靠。
实操建议:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
-
mallinfo在多线程下结果不精确,只反映主线程调用时的快照,且不包含mmap分配的大块内存(如>128KB的malloc请求) - 若需包含所有堆相关内存,优先解析
/proc/self/status中的VmData(数据段)和VmStk(栈)之外的VmSize减去代码/共享库等,但更准的是VmRSS+Swap—— 不过这属于物理内存,不是“已分配堆”逻辑值 - 简单调试可用
malloc_stats()打印到stderr,但无法捕获为变量,仅适合日志观察
macOS和Windows没有标准C++接口,得靠平台API
C++标准库根本不提供获取堆大小的接口,跨平台方案不存在。macOS必须用malloc_zone_statistics查默认zone;Windows则依赖GetProcessHeap + HeapWalk遍历,开销大且需管理员权限才能获取完整信息。
立即学习“C++免费学习笔记(深入)”;
常见错误现象:有人尝试用std::allocator的静态计数器或重载operator new做全局统计,但漏掉第三方库(如Boost、Qt)内部的malloc调用,结果严重偏低。
实操建议:
- macOS下先调
malloc_default_zone(),再传给malloc_zone_statistics,关注size_in_use字段(不是total_size) - Windows下
HeapWalk可能失败(返回FALSE且GetLastError()为ERROR_NO_MORE_ENTRIES),需循环直到遍历完毕;且默认堆以外的私有堆(如CRT创建的)不会被计入 - 不要依赖
_msize(MSVC)或malloc_usable_size单个指针——它们只返回该块实际可用大小,无法汇总
/proc/self/statm和/proc/self/status是Linux最稳的 fallback
当glibc接口不可靠或需绕过运行时库时,直接读取/proc/self/statm是最轻量、最稳定的方式。它以空格分隔7个字段,第1个是总内存页数(含代码、数据、堆、mmap),第2个是驻留页数;而/proc/self/status中MMU无关字段更明确:Heap没这个字段,但VmData(数据段+堆)和VmStk(栈)加起来可粗略代表“用户态堆+全局数据”大小。
性能影响极小,无函数调用开销,且不受多线程干扰。但要注意:VmData包含BSS段和未初始化全局变量,不一定全是malloc分配的。
实操示例(读/proc/self/statm):
FILE *f = fopen("/proc/self/statm", "r");
if (f) {
long size, resident;
fscanf(f, "%ld %ld", &size, &resident);
fclose(f);
// size * getpagesize() ≈ 进程总虚拟内存(KB)
}关键点:必须乘getpagesize(),不能硬编码4096——某些ARM或RISC-V系统页大小不同。
别混淆“已分配堆”和“已使用堆”,多数场景真正要的是后者
用户常以为“已分配堆”等于malloc成功返回的总和,但实际glibc会预留额外空间用于管理元数据、对齐、以及应对后续小分配——mallinfo.arena比mallinfo.uordblks大20%~50%很常见。而uordblks才是当前确实被用户持有的字节数。
容易被忽略的地方:
- 频繁
new/delete后,uordblks可能很小,但arena居高不下——这是glibc的内存复用策略,不是泄漏 - 用
mmap(MAP_ANONYMOUS)分配的大内存块不计入mallinfo,但会计入/proc/self/status的VmSize - ASLR启用时,每次启动
/proc/self/maps中堆地址范围不同,但statm值不受影响
真要监控泄漏,得长期对比uordblks趋势,而不是盯着某个瞬时绝对值。

















