valgrind需重点关注leak summary末三行:definitely lost必须修复,indirectly lost需连带处理,still reachable通常可忽略;非零definitely lost时,向上查找==数字== by行定位main.cpp:15等源码位置;遇invalid错误须加--track-origins=yes追查未初始化源头;输出过长应重定向至文件并用grep精准筛选。

直接看 LEAK SUMMARY 最后三行
Valgrind 运行完输出很长,但真正需要你立刻关注的只有结尾处的 LEAK SUMMARY 段落。它像一份体检报告的“结论页”,其他全是过程数据。
重点盯这三类字段:
-
definitely lost:必须处理。说明内存已彻底丢失(没指针指向它,也没释放),是真实泄漏 -
indirectly lost:跟着上面那个一起修,通常是结构体成员或容器元素连带泄漏 -
still reachable:一般可忽略。比如全局 vector 里还存着对象、单例缓存未清——程序退出前仍能访问,不是 bug
如果这三项都是 0 bytes in 0 blocks,基本可以合上终端了;只要 definitely lost 非零,就得继续往下翻找调用栈。
往上翻,找 ==数字== by 行里的 .cpp 文件和行号
在 LEAK SUMMARY 之前,Valgrind 会列出每块泄漏内存的分配路径。关键线索藏在形如这样的行里:
==12345== by 0x401156: main (main.cpp:15)
这个 main.cpp:15 就是你该去改代码的地方。注意:
- 行号准确的前提是编译时加了
-g;没加的话这里显示的是???:???或汇编地址 - 如果看到多层调用(比如
foo()→bar()→malloc),优先检查最靠近malloc/new的那一层函数 - 第三方库(如 OpenCV)的调用栈常出现在底部,别被它带偏——你的代码通常在倒数第二或第三层
遇到 Invalid read/write 或 Conditional jump 报错,必须加 --track-origins=yes
这类错误不报泄漏,但更危险:越界读写、用未初始化变量做判断,往往导致崩溃或随机行为。典型提示:
Invalid read of size 4 Conditional jump or move depends on uninitialised value(s)
但默认输出只告诉你“出问题了”,不告诉你“值从哪来”。这时候必须重跑:
valgrind --track-origins=yes --leak-check=full ./app
加上 --track-origins=yes 后,Valgrind 会多追查一步,告诉你未初始化的值最初是从哪一行赋的(比如 int x; 声明后没赋值,就直接用了)。
输出刷屏看不完?立刻重定向到文件
大型项目一跑 Valgrind,终端几十屏根本来不及反应,而且滚动条拉上去容易漏关键行。别硬扛,直接导出:
valgrind --leak-check=full --log-file=valgrind.log ./app
跑完打开 valgrind.log,用 grep 快速定位:
grep "definitely lost" valgrind.log-
grep -A 5 "main.cpp" valgrind.log(查含文件名的行及后5行) -
grep -n "by.*:" valgrind.log(快速跳转调用栈位置)
最后提醒一句:Valgrind 报的 still reachable 和第三方库里一堆 possibly lost,多数时候不是你的锅——先聚焦自己代码里明确标出的 definitely lost 和 Invalid 类错误,别的先放一放。











