malloc_stats()是glibc提供的轻量级堆快照接口,输出已分配/空闲字节数、系统申请内存及chunk分布等摘要信息,但仅限glibc、不可编程解析且不支持跨平台。

Linux 下用 malloc_stats() 快速打印基础堆分配摘要
标准 C++ 没有内置接口获取“详细堆内存指标”或“分级统计图表”,malloc_stats() 是 GNU libc 提供的最轻量级手段,能立刻看到当前 malloc 管理器的全局快照:已分配字节数、空闲字节数、系统向内核申请的总内存(sbrk 或 mmap)、以及 chunk 数量分布。它不依赖第三方库,但输出是纯文本、无结构、不可编程解析。
- 必须在程序中显式调用,且仅对 glibc 有效(musl、Android bionic 不支持)
- 输出直接写到
stderr,不能重定向到字符串;如需捕获,得用dup2()临时重定向stderr - 它不区分对象类型、不记录分配栈、不显示内存碎片率,仅反映
malloc自身的管理状态 - 示例调用:
malloc_stats(); // 输出类似:Arena 0: system bytes = 135168, in use bytes = 123456
用 mallinfo() 或 mallinfo2() 获取可编程的数值指标
比 malloc_stats() 更进一步,mallinfo() 返回 struct mallinfo,含 uordblks(已分配字节数)、fordblks(空闲字节数)等字段;但它在 glibc 2.33+ 已被标记为废弃,因字段定义模糊、32 位溢出风险高。推荐改用 mallinfo2()(glibc ≥ 2.33),返回 struct mallinfo2,所有字段为 size_t,无截断问题。
-
mallinfo2()仍只提供粗粒度汇总值,无法按 size class 或调用点分类 - 字段如
smblks(小块缓存数)、hblks(mmap 分配的 arena 数)实际意义依赖 glibc 版本实现,文档不保证稳定 - 注意:这些函数统计的是
malloc管理层视角,不包含new运算符可能绕过的自定义分配器行为 - 简单读取示例:
struct mallinfo2 mi = mallinfo2();<br>printf("in use: %zu bytes\n", mi.uordblks);
真正分级统计必须介入分配器:LD_PRELOAD hook malloc/free
要获得“按分配大小区间”“按调用栈”“按源文件行号”的分级统计,唯一可靠方式是拦截所有堆分配入口。Linux 下最常用的是 LD_PRELOAD 注入自定义 malloc 实现,或使用现成工具如 gperftools(tcmalloc)的 HeapProfiler。
-
gperftools需链接-ltcmalloc_and_profiler,运行时设HEAPPROFILE=/tmp/myapp,会生成.heap文件,再用pprof可导出火焰图或按 size class 分组的 CSV - 自行 hook 需处理线程安全(
pthread_mutex_t或std::atomic计数)、避免递归调用(如malloc内部可能调用malloc) - 关键陷阱:C++
operator new默认调用malloc,但若全局重载了operator new,你的LD_PRELOAD就失效了——必须同时 hookoperator new符号 - 分级统计的“级”通常指 size class(如 8B/16B/32B…),不是自动按业务模块分;想按类名/函数名分,必须采集调用栈(
backtrace()),性能开销极大(每次分配多几微秒)
Windows 或跨平台方案:用 _CrtMemCheckpoint + _CrtMemDifference
Windows Visual C++ CRT 提供调试堆检测能力,适用于开发期诊断,但仅限 Debug 模式、不支持 Release、且完全不兼容 Linux/macOS。
- 启用方式:在
main()开头调用_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF) - 用
_CrtMemState结构体保存快照,_CrtMemDifference对比两次快照,得到新增/未释放块的数量与大小 - 它能报告泄漏块的分配序号(
lRequest),配合_CrtSetBreakAlloc(n)可在第 n 次分配时断点,但无法生成“图表”,只能靠日志人工分析 - 注意:该机制对 STL 容器内部的
malloc调用同样生效,但若项目用了/MTd(静态 CRT),则需确保所有模块一致,否则统计不全
gperftools、Valgrind --tool=massif),要么需要自己构建带采样、符号解析、聚合展示的完整 pipeline。最容易被忽略的一点:**所有用户态堆统计都看不到内核页表层面的真实物理内存占用,更无法反映透明大页(THP)或内存压缩带来的偏差**。C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











