valgrind 默认 --leak-check=summary,仅统计泄漏总量,不显示具体调用栈,无法定位泄漏代码位置;必须显式设为 full 并配合 --show-leak-kinds=all 等参数才能完整检测。

leak-check 默认值是什么,不设会漏掉什么
Valgrind 默认开启 --leak-check=summary,只统计泄漏总量(如 “definitely lost: 128 bytes”),不列出具体调用栈。这意味着你根本看不到哪行代码 malloc 了但没 free —— 对定位问题毫无帮助。
实际调试内存泄漏时,必须显式设置更严格的检查级别:
-
--leak-check=full:显示每一块泄漏内存的完整堆栈(最常用) -
--leak-check=summary:仅汇总数字,适合快速过筛,但无法 debug -
--leak-check=partially:已废弃,Valgrind 3.20+ 会忽略并警告
为什么 --leak-check=full 还可能找不到泄漏
即使设了 --leak-check=full,仍可能“查不到泄漏”,常见原因有:
- 程序没正常退出:Valgrind 只在进程 exit 或调用
VALGRIND_DO_LEAK_CHECK时触发检查;如果程序卡死、被 kill 或用_exit()强退,泄漏不会上报 - 泄漏发生在 fork 子进程中,而父进程先退出:Valgrind 默认只检查主进程,子进程需单独运行或加
--trace-children=yes - 使用了自定义分配器(如 jemalloc、tcmalloc)且未正确拦截:Valgrind 默认只 hook libc 的 malloc/free,其他分配器需额外配置或换用
--tool=memcheck兼容模式
--leak-check 配套必须加的参数
单靠 --leak-check=full 不够,这几个参数几乎总是要一起用:
-
--show-leak-kinds=all:默认只报definitely lost和possibly lost,漏掉still reachable(比如全局指针指向的缓冲区)和suppressed(被 suppress 文件过滤的) -
--track-origins=yes:对possibly lost类泄漏,能指出内存最初从哪分配、又被谁覆盖了指针 -
--verbose:看到 Valgrind 加载了哪些符号、是否找到 debug info;如果堆栈全是 ??,大概率是没编译 -g 或 strip 过
典型命令长这样:
valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --verbose ./my_program
泄漏报告里 still reachable 算不算 bug
算不算,得看场景:
- 全局缓存、日志缓冲区、单例对象内部持有的内存,在程序生命周期内一直可达 ——
still reachable是预期行为,一般不用处理 - 但如果是某个函数反复调用后,
still reachable内存持续增长,说明本该释放的资源被长期持有(比如忘了从哈希表删除节点),这就属于隐性泄漏 - Valgrind 不会自动区分“合理持有”和“意外累积”,得靠你结合代码逻辑判断堆栈里的模块归属
真正容易被忽略的是:still reachable 在默认设置下不显示,必须加 --show-leak-kinds=all 才会出来 —— 很多人以为没泄漏,其实是被过滤掉了。











