Valgrind和AddressSanitizer(配合LeakSanitizer)是唯一能精准定位内存泄漏分配点文件与行号的可靠方案;Valgrind需-g编译、禁用LTO和高优化,运行时用--leak-check=full参数;ASan须显式启用-leak选项,否则不检测泄漏。

内存泄漏无法靠读代码或日志精准定位,必须依赖运行时检测工具;Valgrind 和 AddressSanitizer(配合 LeakSanitizer)是目前唯一能给出「分配点文件+行号」的可靠方案,其他方法(如重载 new、malloc hook)在真实项目中基本不可信。
Valgrind memcheck 怎么跑才不白跑
Valgrind 不是编译期检查,它把程序放进虚拟 CPU 环境里全程监控堆操作。常见失败原因不是工具不行,而是环境没配对:
- 必须用
-g编译,否则报告里只有地址,没有test.cpp:42这种信息 - 禁用
-flto(LTO 链接时优化),否则符号被抹掉,definitely lost只显示???:??? - 别用
-O2或更高优化等级,-O0最稳妥,-O1在部分版本下也可接受 - 运行命令要带完整参数:
valgrind --leak-check=full --show-leak-kinds=all ./your_program -
definitely lost是你要修的——指针彻底丢了,比如new后没delete,或unique_ptr没 move 出作用域就结束了
AddressSanitizer 怎么开泄漏检测才生效
ASan 默认只查越界和 UAF,**不查泄漏**;必须显式启用 LeakSanitizer(LSan),否则跑完啥也不报:
- 编译加
-fsanitize=address,leak,不是-fsanitize=leak(后者无效) - 必须加
-g,否则泄漏报告里看不到源码位置 - 推荐用
-O1,-O2可能导致漏报(编译器优化掉部分分配路径) - 运行后等程序退出,才会输出
LeakSanitizer: detected memory leaks—— 如果没这行,说明 LSan 根本没触发 - 动态库(
.so)也要用同样 Sanitizer 选项编译,否则其内部泄漏不会显示源码行号
为什么自己重载 operator new 定位不准
看似可控,实则覆盖不全、多线程不安全、极易误判:
- Qt、Boost、std::string 内部缓冲区等可能绕过 global
new,走自定义分配器或 mmap,你的计数完全不包含它们 - 第三方库调用
malloc而非new,你重载new就等于没装监控探头 - 多线程下没加锁写全局 map,
insert和erase并发会 crash,反而引入新 bug - 程序退出时未释放的内存,你统计出来 ≠ 泄漏,可能是全局对象或运行时缓存(
still reachable类型)
真正难的不是“找到泄漏”,而是区分「泄漏」「缓存膨胀」和「堆碎片」——三者 RSS 都涨,但修复手段完全不同。空负载下 RSS 不回落,才值得上 Valgrind 或 ASan;否则先看容器 size、缓存淘汰逻辑、分配器配置更省时间。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











