
用 Valgrind 检查 Linux 下的 C++ 内存泄漏
Valgrind 是 Linux 环境下最直接有效的内存泄漏检测工具,它不依赖源码修改,能定位到 malloc、new 未配对释放的具体行号。但要注意:必须用 -g 编译,且关闭优化(-O0),否则行号错乱或漏报。
典型使用流程:
- 编译:
g++ -g -O0 -o myapp main.cpp - 运行检测:
valgrind --leak-check=full --show-leak-kinds=all ./myapp - 重点关注输出中
definitely lost和possibly lost的块,它们对应真实泄漏
常见误判点:静态对象析构晚于 Valgrind 报告时机,可能被标为 still reachable——这通常不是泄漏,无需修复。
Windows 下用 CRT 调试堆检测 _CrtDumpMemoryLeaks()
Windows Visual Studio 自带的 CRT 调试堆能在程序退出时自动报告堆分配差异,前提是启用调试堆并正确设置检查点。
立即学习“C++免费学习笔记(深入)”;
关键操作:
- 包含头文件:
#include - 在
main()开头调用:_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); - 或手动在退出前加:
_CrtDumpMemoryLeaks();
注意:必须用 Debug 模式编译(/MDd 或 /MTd),Release 模式下 _Crt* 函数为空实现;另外,全局对象的 new 可能早于 _CrtSetDbgFlag 调用,导致漏检,建议把检查点放在 main() 最开头。
智能指针不是万能解药:shared_ptr 循环引用怎么破
std::shared_ptr 自动管理生命周期,但两个对象互相持有对方的 shared_ptr 会导致引用计数永不归零——这就是循环引用泄漏。
典型场景:
- 父子结构(如树节点中父指针和子指针都用
shared_ptr) - 观察者模式中,被观察对象持观察者的
shared_ptr,观察者又持被观察对象的shared_ptr
解决办法只有两个:
- 一方改用
std::weak_ptr(推荐):它不增加引用计数,访问前用lock()检查是否还有效 - 明确所有权,改用裸指针或
std::unique_ptr(例如父节点用unique_ptr管理子节点,子节点用裸指针回指父节点)
别试图用 shared_ptr::reset() 手动打断——时机难控,容易引发 use-after-free。
new[] / delete[] 不配对是静默崩溃的常见原因
用 new[] 分配数组,却用 delete(无方括号)释放,C++ 标准规定行为未定义:可能当场崩溃,也可能看似正常但破坏堆元数据,后续分配/释放随机失败。
避免方式很实际:
- 优先用
std::vector或std::array替代原始数组 - 若必须用动态数组,封装成 RAII 类型(如自定义
ArrayWrapper),或直接用std::unique_ptr——它会自动调用delete[] - Clang/GCC 加上
-fsanitize=address可在运行时报出这类不匹配(ASan 会拦截并提示heap-use-after-free或mismatched free)
ASan 不仅抓泄漏,更擅长发现释放不匹配、越界访问等“非泄漏但更危险”的问题,建议日常开发开启。










