Valgrind检测核心是看LEAK SUMMARY中“definitely lost”字节数和ERROR SUMMARY中非零error数;前者表明确定内存泄漏,后者对应非法访问等运行时错误,其余调用栈仅为定位依据。

先看最后的 LEAK SUMMARY 和 ERROR SUMMARY
Valgrind 输出长不是因为错得多,而是它把每条错误的调用栈都展开成十几行。真正需要你动手改的,其实就藏在最底部那几行总结里。
重点盯住这两块:
-
LEAK SUMMARY里definitely lost的字节数 —— 这是铁证如山的泄漏,必须处理 -
ERROR SUMMARY里非零的 error 数(比如1 errors from 1 contexts)—— 每个 error 对应一个真实运行时违规,比如Invalid write或Use of uninitialised value
其它全是“证据链”,用来定位问题在哪一行。没看到这两个 summary 就往下翻,等于在迷宫里不看出口指示牌。
遇到第三方库刷屏报错,直接跳过中间堆栈
像 OpenCV、Boost、Qt 这类库,常有全局单例或延迟释放逻辑,Valgrind 会把它们标成 still reachable 或 possibly lost,但实际不是你的 bug。这类报告往往占满屏幕 90% 篇幅。
快速过滤办法:
- 用
grep -A5 -B5 "definitely lost\|Invalid read\|Invalid write\|Use of uninitialised"直接抓关键错误 - 加
--suppressions=opencv.supp抑制已知第三方误报(Valgrind 自带部分 suppressions,也可手写) - 检查报错中是否含
in /usr/、libopencv、libstdc++等路径 —— 出现在这些路径里的调用帧,基本可跳过
真正的泄漏或越界,几乎总出现在你自己的源文件路径里,比如 main.cpp:42 或 parser.h:88。
“Conditional jump or move depends on uninitialised value” 必须加 --track-origins=yes
这条错误本身只告诉你“用了未初始化值”,但不告诉你这个值从哪来。不加参数的话,你只能看到出问题的函数,看不到源头赋值语句。
正确做法:
- 重跑命令:
valgrind --track-origins=yes --leak-check=full ./app - 报告里会出现类似这样的两段式输出:
==12345== Conditional jump or move depends on uninitialised value(s)==12345== at 0x4012AB: process_data (logic.cpp:67)==12345== Uninitialised value was created by a stack allocation==12345== at 0x4011F0: main (main.cpp:23)
第二段的 Uninitialised value was created by... 才是你该去修的地方 —— 往上翻到 main.cpp:23,大概率是某个局部变量声明了但没赋初值。
别信 “still reachable”,但要确认它真不是你的错
still reachable 多数情况是安全的:比如 static std::vector<int> cache; 在程序退出前没清空,OS 会回收,Valgrind 只是照实汇报。
但有两种例外容易被忽略:
- 你手动
new了一个对象,存进全局容器(如std::map<int, Foo*> g_objs;),但没在 exit 前delete—— Valgrind 会记作still reachable,但它其实是你的泄漏 - 使用了
std::shared_ptr但存在循环引用,导致资源无法析构 —— 表现也是still reachable,但内存实际没释放
判断方法:看分配栈里有没有你自己的 .cpp 文件名和 new/malloc 调用。有,就得查;全是系统或标准库路径,才放心忽略。


















