linux下快速查看堆使用概况应优先用malloc_info导出xml分级统计,mallinfo和malloc_stats仅反映全局状态且字段易误读,二者均不统计mmap内存;生产环境推荐结合/proc/pid/smaps与受限mtrace采样。

Linux下用mallinfo和malloc_stats快速看堆使用概况
这两个是glibc原生接口,不用额外依赖,但只能反映当前进程的全局堆状态,无法区分对象类型或调用栈。它们适合快速诊断是否内存持续增长、是否存在大量未释放小块内存。
常见错误是直接调用mallinfo后误读字段:比如arena是主分配区大小(含已分配+空闲),而uordblks才是已分配字节数;fordblks是空闲字节数,不是“可用总内存”。malloc_stats()则直接打印到stderr,不能捕获为字符串——若需日志记录,得重定向stderr或改用malloc_info(3)。
-
mallinfo返回结构体字段含义模糊,不同glibc版本字段名有差异(如smblks在2.34+已弃用) -
malloc_stats()输出无结构化格式,不适合自动化解析 - 二者均不统计mmap分配的内存(如大块内存会绕过malloc直接mmap)
用malloc_info导出XML并解析分级统计
这是目前最实用的方案:它能按内存池(heap)、分配区(arena)、bin(small/large)分层输出,且支持指定文件描述符,可写入内存缓冲区再解析。
关键点在于调用时传入FD而非依赖stdout,避免干扰程序正常输出。示例中常用open("/dev/shm/malloc_info.xml", O_RDWR|O_CREAT, 0600)临时写入再读取,比pipe更稳定。
- 必须用
malloc_info(0, fd)中的0表示“默认格式”,传1会输出更简略的格式(丢失bin级细节) - XML中
<small></small>和<large></large>对应不同分配策略,nr_blocks和total_size才是有效统计项,max_size只是历史峰值 - 注意
arena数量可能远大于1(多线程下每个线程可能有自己的arena),需遍历所有<heap></heap>节点
编译期启用malloc调试:加-D_GLIBCXX_DEBUG或链接libefence
这不是运行时指标采集,而是让每次malloc/free附带校验与记录——适用于定位泄漏或越界,但性能开销极大(10倍以上 slowdown),绝不可用于线上。
真正有用的是libefence(Electric Fence):它把每次分配放在独立页边界,一旦越界立即触发SEGV;配合addr2line能精确定位分配点。但它不提供统计汇总,只报错。
-
-D_GLIBCXX_DEBUG仅影响std::vector等容器的new调用,对裸malloc无效 - 启用
libefence需在链接时加-lefence,且必须放在-lc之前,否则符号覆盖失败 - 所有调试工具都绕不开
LD_PRELOAD方式注入,但会与ASLR、PIE等机制冲突,某些情况下导致进程启动失败
生产环境推荐:用proc/<pid>/smaps</pid>结合mtrace做轻量级分级采样
/proc/<pid>/smaps</pid>给出的是内核视角的内存映射,其中MMAP、Heap、Anonymous三类区域可粗略对应用户态堆行为;而mtrace是glibc内置的跟踪机制,只需设置MALLOC_TRACE环境变量并调用mtrace(),就能生成分配/释放调用栈日志。
问题在于mtrace日志是纯文本,每行类似@ 0x7f8b3c1a2000 0x401234 32,需用memusage工具解析——但该工具已废弃,现在得自己写脚本按地址匹配objdump -t符号表。更现实的做法是只在关键路径前后调用mtrace/muntrace,限制日志体积。
-
smaps里的Rss≠实际堆使用量,它包含共享库、stack、mmap等全部驻留内存 -
mtrace不记录分配大小以外的信息(如类型名、所属模块),无法自动聚类 - 分级统计真正落地时,往往要结合
backtrace()+dladdr()在分配钩子里打点,但这要求替换malloc符号,风险高
mallinfo能告诉你“哪个类占了多少内存”——它根本做不到。真要按类型归因,得从源头控制:要么用自定义分配器绑定类型ID,要么依赖LLVM的-fsanitize=address配合ASAN_OPTIONS=allocation_context=1生成调用栈快照。这些都不是“获取指标”,而是重构内存管理契约。C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











