必须加 --leak-check=full 而非 yes,因 yes 仅报告 definitely lost,漏掉 indirectly/possibly lost;full 展开全部栈帧,精确定位 malloc 源码行;--show-leak-kinds=all 是必要条件,否则间接和可能泄漏被静默过滤。

直接用这组参数组合,覆盖 95% 的内存泄漏排查场景: valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all --track-origins=yes --verbose ./your_program
为什么必须加 --leak-check=full 而不是 yes
虽然 --leak-check=yes 也能触发检测,但它默认只显示“definitely lost”类泄漏,会漏掉间接泄漏(indirectly lost)和可能泄漏(possibly lost)。而 full 强制展开所有栈帧、显示完整调用路径,能准确定位到 malloc 发生的那行代码——没有它,你只能看到 malloc 在 libc 里,看不到自己写的哪一行。
--show-leak-kinds=all 不是可选项,是必要条件
Valgrind 把泄漏分成四类:definitely、indirectly、possibly、reachable。只开 full 不开 all,indirectly 和 possibly 就被静默过滤了。比如一个指针被存在全局结构体里但没清空,就属于 possibly lost,不加这个参数你就完全看不到。
--track-origins=yes 对未初始化内存问题关键,但对泄漏本身无直接帮助
这个参数只影响 Use of uninitialised value 类错误的溯源,和内存泄漏无关。但它常和泄漏一起出现(比如用未初始化指针去 free),所以建议保留;不过要清楚:它会让 Valgrind 运行变慢 2–3 倍,纯查泄漏时可临时去掉。
容易踩的坑:日志重定向和子进程
- 输出太长刷屏?用
--log-file=valgrind.log保存,别依赖终端滚动 - 程序 fork 了子进程且泄漏在子进程中?必须加
--trace-children=yes,否则子进程的malloc完全不监控 - 编译没加
-g?所有文件名和行号都显示为???,再全的参数也白搭 - 用了
-O2或更高优化?函数内联可能导致栈回溯断裂,-O0是底线
复杂点在于:泄漏类型判断依赖上下文。比如 reachable 看似安全,但如果是指向大 buffer 的全局指针且生命周期远超实际需要,就是隐性资源浪费——Valgrind 不报错,但得靠人看懂报告里的“still reachable”后面跟着的 size 和调用栈。











