复测前必须重新编译带-g的可执行文件,因valgrind依赖调试符号定位行号;应组合使用--leak-check=full、--show-leak-kinds=all和--track-origins=yes;重点核查heap summary中in use at exit值是否归零及分配/释放数量差,并警惕suppressed错误掩盖真实问题。

复测前必须重新编译带 -g 的可执行文件
Valgrind 报告依赖调试符号定位问题行号,如果修完代码后直接拿旧二进制跑,valgrind 仍会显示老的堆栈(比如 main (memory_leak.c:6)),但实际代码已改——这会导致你误判“问题还在”,或漏掉新引入的路径。务必确认:修改源码 → gcc -g -o program program.c → 再用 valgrind 运行新生成的 program。
--leak-check=full 和 --show-leak-kinds=all 要一起用
只开 --leak-check=full 时,默认不报告 possibly lost 和 still reachable 类型泄漏,而这类泄漏在嵌入式或长期运行服务中同样危险。真实复测场景下,应固定组合使用:
-
--leak-check=full:展开每一块泄漏的调用栈 -
--show-leak-kinds=all:不放过definitely lost、indirectly lost、possibly lost、still reachable -
--track-origins=yes:对Use of uninitialised value类错误,能定位到变量首次赋值位置
关注 HEAP SUMMARY 里 in use at exit 的数值变化
别只扫一眼 “no leaks are possible” 就放心。重点看这一行:
==12345== in use at exit: 0 bytes in 0 blocks
如果修复后仍是非零值,说明还有未覆盖路径;如果从 40→8 字节,说明只修了一部分分配点。另外注意:
-
total heap usage: 10 allocs, 9 frees—— 分配/释放数量差 1,大概率漏了free -
still reachable不等于安全:它常是全局指针指向的内存,进程退出时没显式释放,但在守护进程中可能持续累积 - 多线程程序要加
--tool=helgrind单独跑一次,memcheck不检测竞态
避免被 suppressed 信息误导
复测时如果看到 ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 5 from 5),别以为万事大吉。这些被抑制的错误可能是你之前手动加的 .supp 文件规则,也可能是系统库(如 glibc)的已知误报。真正要盯的是:
- 未被抑制的
definitely lost是否清零 - 新增的
Invalid read/write是否出现(说明修复引入了新越界) - 日志末尾是否有
For counts of detected and suppressed errors, rerun with: -v—— 加-v看被抑制项详情,确认不是掩盖了真问题
复杂点在于:有些泄漏只在特定输入路径触发,单次复测容易漏。建议配合最小化测试用例 + 覆盖关键分支的输入参数组合再跑一遍。











