“definitely lost: 0 bytes”不等于无泄漏,因强制终止、线程未join、thread_local内存、漏配--show-leak-kinds=all等均会导致真实泄漏被忽略;关键看HEAP SUMMARY中“in use at exit”是否为零及调用栈顶部是否为用户源文件。

“definitely lost: 0 bytes in 0 blocks”不等于没泄漏
这行输出只说明 Valgrind 在进程 clean exit 后没找到「确定丢失」的内存,但完全可能漏掉真实泄漏。常见原因包括:
— 程序因 SIGSEGV、abort() 或被 kill -9 强制终止,Valgrind 来不及扫描;
— 多线程程序中子线程未 join() 就退出,其分配的内存被记为 possibly lost 或直接忽略;
— 使用了 thread_local 变量内部 new 的内存,线程退出时析构函数没手动 delete,Valgrind 不会追踪 TLS 区域的堆分配;
— --leak-check=full 没配 --show-leak-kinds=all,导致 possibly lost 和 still reachable 被静默隐藏。
真正该盯住的是 “in use at exit” 和调用栈顶部的源文件名
看报告末尾的 HEAP SUMMARY 部分:
— in use at exit: X bytes in Y blocks 是关键指标,只要非零,就说明有未释放内存残留;
— 如果 definitely lost 是 0,但 possibly lost 或 still reachable 非零,得点开对应 leak record,重点看调用栈最上面几行是不是你自己的 .cpp 或 .c 文件;
— 出现在 libc.so.6、libstdc++.so 或 vg_replace_malloc.c 里的泄漏,大概率是标准库缓存机制(如 std::string 的 small string optimization 缓冲池),不用修;
— suppressed: N bytes in M blocks 表示已被 Valgrind 内置抑制规则过滤,可直接跳过。
valgrind --leak-check=full 必须配合其他参数才完整
单独用这个参数容易误判:
— 一定要加 --show-leak-kinds=all,否则默认只报 definitely lost;
— 多线程必加 --track-origins=yes 和 --read-var-info=yes,否则指针来源无法追溯;
— 若看到大量 ??? 行号,说明编译没加 -g -O0,调试符号失效;
— 验证符号是否有效:运行 file ./app,输出里要有 with debug_info;再跑 nm -C ./app | grep main,应能列出 main 符号。
“All heap blocks were freed”才是安全信号
这句话出现在报告底部,比 definitely lost: 0 更可靠:
— 它表示 Valgrind 扫描到所有 malloc/new 都有对应的 free/delete;
— 但前提是程序必须走到 return 0 或显式调用 exit(0);
— 如果程序逻辑里有 exit(1)、longjmp 或信号 handler 中提前退出,这句话就不会出现;
— 真正难的不是读报告,而是让程序在 Valgrind 下「走完所有路径并 clean exit」——加日志、删 assert、补 join(),都是为了这个目标。


















