最可靠方法是用 valgrind --leak-check=full 检测,但必须在 Linux 下编译时加 -g、运行不跳过 main() 退出;否则漏报“程序结束前未释放”的泄漏,且无源码行号定位。

直接用 valgrind 检测最可靠,但必须在 Linux 下、编译时加 -g、运行时不跳过 main() 退出——否则漏掉“程序结束前未释放”的泄漏根本不会报。
valgrind --leak-check=full 必须配合 -g 编译
不加 -g 时,valgrind 只能告诉你 “operator new 在 libc 中被调用”,无法定位到你的 main.cpp:12;加了之后,输出里会出现明确的源码行号和函数名。这不是可选项,是硬性前提。
-
g++ -g -o myapp myapp.cpp—— 编译命令里必须含-g - 如果项目用 CMake,确认
CMAKE_BUILD_TYPE是Debug或手动加set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g") - 静态库/第三方代码没带调试信息?
valgrind仍能检测泄漏,但调用栈会断在库入口,你得靠自己代码的分配点反推
new 和 new[] 必须分别匹配 delete 和 delete[]
valgrind 能区分 definitely lost(确定泄漏)和 still reachable(全局指针还活着),但不会替你检查配对错误。错用 delete 释放 new[] 分配的内存,它报的是 Invalid free 或 Mismatched free,不是泄漏——这类问题往往伴随崩溃,比泄漏更紧急。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 看
valgrind输出里的operator new[](unsigned long)还是operator new(unsigned long),对应检查释放处 - STL 容器(如
std::vector)内部用new[],你不需要、也不应该手动释放它的内部指针 - 用
std::unique_ptr<int[]>替代裸new int[N],从根源上规避配对风险
泄漏报告里 “still reachable” 不等于安全
很多开发者看到 still reachable 就以为没问题,其实不然。它只表示:程序退出时,还有指针能访问那块内存,但不保证这个指针后续还会被用来 delete。比如全局 std::map<int*, int> 存了堆地址却忘了清空,就属于典型 still reachable 泄漏。
立即学习“C++免费学习笔记(深入)”;
-
valgrind默认不报告still reachable,要显式加--show-leak-kinds=all - 这类泄漏在长期运行服务中会持续增长,尤其在 reload 配置或热更新模块后容易复现
- 检查所有全局容器、单例对象的析构逻辑,确保它们在程序退出前清空自身持有的堆资源
真正难抓的是那些只在特定路径触发、且分配后很快被覆盖指针的泄漏——valgrind 能报出来,但你需要结合条件断点和小范围复现才能锁定。别依赖“一次全量扫描”,把它当成一个必须嵌入日常开发节奏的反馈环节。

















