valgrind报告“干净”需同时满足:error summary: 0 errors且definitely lost: 0 bytes in 0 blocks,并确保--leak-check=full已启用、程序正常退出;still reachable可接受,但all heap blocks were freed不能替代详细检查。

一份 Valgrind memcheck 报告是否“干净”,不看有没有输出,而要看有没有 **真实、未被忽略的错误条目**。只要报告末尾的 Summary 区域显示 ERROR SUMMARY: 0 errors from 0 contexts 且 definitely lost: 0 bytes in 0 blocks,才可初步认为内存行为是干净的——但这个判断本身有陷阱,得结合上下文细看。
看 Summary 里的 ERROR SUMMARY 和 leak summary 是否全为零
Valgrind 报告结尾固定有一段 Summary,这是最直接的判断依据:
-
ERROR SUMMARY: X errors from Y contexts—— 这里的X必须为0,否则说明存在运行时内存违规(如越界读写、use-after-free、invalid free) -
definitely lost:,possibly lost:,still reachable:这三行字节和块数都应为0(或你明确接受still reachable) -
suppressed:行数字不重要,它只统计被 suppress 文件过滤掉的已知误报
注意:still reachable 不等于 bug。比如全局 std::string 或 pthread 库内部缓存,在 main 返回后仍持有指针,属于正常现象。除非你主动调用 exit() 前强制释放所有资源,否则不必为它焦虑。
警惕 “no errors” 但 leak-check 被关掉的情况
很多人跑出 ERROR SUMMARY: 0 errors 就以为万事大吉,却没发现根本没开泄漏检测:
- 默认情况下
--leak-check是summary级别,只报总数,不列具体位置;--leak-check=no则完全不检查泄漏 - 必须显式加
--leak-check=full才能触发详细泄漏分析,否则definitely lost那几行压根不会出现 - 如果命令里漏了
--leak-check=full,Summary 里可能只显示ERROR SUMMARY: 0 errors,但泄漏字段直接缺失——这不是干净,是没查
正确启动命令至少要包含:valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all ./myapp
识别被误判为“干净”的常见假象
有些报告看似干净,实则掩盖了问题:
- 程序在检测中途崩溃(如 segfault),Valgrind 来不及输出 leak summary —— 此时看开头是否有
Invalid read of size X或Process terminating with default action,这类中断意味着检测被强制终止,结果不可信 - 用了
--suppressions=xxx.supp却 suppress 掉了真实问题,比如把definitely lost条目也包进去了,Summary 就会失真 - C++ 中
new/delete不匹配(如new[]配delete)可能只报Mismatched free() / delete / delete [],但它归在 ERROR SUMMARY 里,不是 leak summary,容易被忽略
真正干净的报告,是既没有 ERROR SUMMARY 报错,又在 leak summary 里确认 definitely lost: 0,且程序完整跑完退出(exit code 0)。
为什么不能只信 “All heap blocks were freed” 这句话
Valgrind 有时会在 Summary 末尾补一句:All heap blocks were freed -- no leaks are possible。这句话极具迷惑性:
- 它只表示“当前已分配的堆块全部被 free 了”,但不保证这些 free 发生在正确时机、由正确线程执行、或没发生重复释放
- 它不检查
still reachable的块是否本该在 exit 前释放(比如单例对象持有的缓冲区) - 它完全不覆盖栈内存、mmap 分配、或文件描述符等非堆资源泄漏
所以这句话只能当辅助提示,不能替代对 definitely lost 和 ERROR SUMMARY 的逐项核对。线上长期运行的服务,哪怕报告里写着这句话,也建议加 --track-origins=yes 多跑一轮,确认没遗漏未初始化值传播路径。











