mtrace是gnu c库(glibc)自带的轻量级内存泄漏检测工具,专用于定位由malloc、calloc、realloc分配且未被free释放的堆内存泄漏,不支持new/delete、mmap及栈/静态内存。

mtrace 是什么,它能帮你定位哪类内存泄露
mtrace 是 glibc 提供的一个轻量级内存追踪工具,专用于捕获 malloc、calloc、realloc 和 free 的调用栈与配对关系。它不抓 C++ 的 new/delete(除非你重载了 operator new 为 malloc 系实现),也不跟踪 mmap 分配的内存或静态/栈内存 —— 它只管堆上由 libc 分配器管理的那一块。
所以如果你的程序大量使用 new,但没重载为调用 malloc,mtrace 就会完全沉默。这是第一个也是最常踩的坑。
启用 mtrace 的三步实操:编译、插桩、跑起来
不是加个 flag 就完事,得手动在代码里插入开关:
- 在程序入口(比如
main())开头调用setenv("MALLOC_TRACE", "mtrace.log", 1),再调用mtrace() - 在程序退出前(比如
main()返回前)调用muntrace()—— 不调的话日志可能不全或损坏 - 编译时必须用
-g(否则堆栈无符号信息),且不要加-O2以上优化(内联可能吞掉调用点,导致行号错乱)
示例片段:
int main() {
setenv("MALLOC_TRACE", "mtrace.log", 1);
mtrace(); // 启动追踪
// ... 你的代码
muntrace(); // 关闭追踪
return 0;
}
解析 mtrace.log:怎么看懂那堆十六进制地址
运行后生成的 mtrace.log 是纯文本,每行形如:@ 0x7f8b3c0012a0 0x401234 123,含义是「在地址 0x401234(即源码某行)分配了 123 字节,指针存于 0x7f8b3c0012a0」;- 0x7f8b3c0012a0 表示该地址被 free。
真正有用的是 mtrace 命令本身(注意不是同名可执行文件,而是 glibc 自带的 Perl 脚本):
- 确保你的二进制有调试符号:
file your_program应显示 “with debug_info” - 运行
mtrace your_program mtrace.log,它会把地址映射回源码文件和行号 - 输出里标为
*** Memory leak detected ***的行,就是没配对free的分配点
如果输出全是地址没源码,八成是没 -g 编译,或者 mtrace 找不到你的可执行文件符号表路径。
常见失效场景和绕过限制的办法
mtrace 对多线程不友好:它内部用全局锁,高并发下日志可能丢失或错序;对 C++ new 默认无效;且无法在动态库初始化阶段(如 __attribute__((constructor)))前开启。
- 若必须追踪
new,可全局重载operator new和operator delete,内部调用malloc/free并同步调用mtrace开关(注意构造函数里不能用new) - 多线程下建议用
LD_PRELOAD方式启动:LD_PRELOAD=/lib/x86_64-linux-gnu/libc.so.6 MALLOC_TRACE=mtrace.log ./your_program,部分版本支持更稳定的钩子 - CI 环境中记得清理
mtrace.log,否则多次运行会追加,mtrace解析时会误报“重复分配”
真正麻烦的从来不是怎么开 mtrace,而是确认你漏掉的那几处 free 是否发生在异常路径、信号处理里,或者被 longjmp 跳过了 —— 这些地方 mtrace 日志里不会体现“为什么没 free”,只告诉你“它没 free”。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











