valgrind默认使用memcheck工具检测内存泄漏、越界、未初始化等错误;指定--tool可切换为cachegrind(缓存分析)、callgrind(调用性能)、helgrind/drd(线程竞争)、massif(堆内存)等专用工具,但每次仅支持一个工具且参数不可混用。

valgrind --tool= 参数决定用哪个工具
Valgrind 默认启动 memcheck,不加 --tool 就等于 --tool=memcheck。要换工具,必须显式指定 --tool,比如查缓存就用 --tool=cachegrind,看函数调用开销就用 --tool=callgrind。
常见可选值包括:memcheck、cachegrind、callgrind、helgrind、massif、drd。每个工具输出格式和用途完全不同,不能混用参数——比如 --leak-check=full 只对 memcheck 有效,传给 callgrind 会直接报错并退出。
-
memcheck:检测内存泄漏、越界、未初始化、重复 free 等,适合开发阶段日常检查 -
cachegrind:输出 cache miss 次数、指令数,不生成错误报告,只生成统计文件(默认cachegrind.out.PID) -
callgrind:生成调用图和每函数耗时,需配合callgrind_annotate解析输出 -
helgrind或drd:专用于多线程竞争检测,但两者不兼容同一份日志,也不能和memcheck同时启用
不能同时启用多个工具
Valgrind 内核一次只能加载一个工具插件。试图写成 valgrind --tool=memcheck --tool=callgrind ./a.out 会导致第二个 --tool 覆盖第一个,最终只运行后者;而像 --leak-check=full --dump-instr=yes 这种跨工具的组合参数,会在启动时被拒绝,报错类似:unrecognised option '--dump-instr=yes'。
如果你需要多种分析结果,必须分多次运行:
- 查内存问题:
valgrind --leak-check=full ./a.out - 看缓存行为:
valgrind --tool=cachegrind ./a.out - 分析线程安全:
valgrind --tool=helgrind --track-lockorders=yes ./a.out
注意:每次运行都是独立仿真,程序会被完整重跑一遍,且性能开销叠加——比如 callgrind 本身就会让程序慢 10–20 倍,再加 -g 编译和大堆栈深度,可能卡住几小时。
工具间参数不能复用,尤其注意 --log-file 和输出路径
不同工具对日志处理方式差异很大:memcheck 默认把错误信息打到 stderr,加 --log-file=xxx 才写入文件;而 cachegrind 默认就写 cachegrind.out.PID,加 --log-file 反而会覆盖默认行为,导致无输出;callgrind 的输出是二进制 profile 数据,必须用 callgrind_annotate 解析,直接打开是乱码。
容易踩的坑:
- 误以为
--leak-check对所有工具都有效 —— 它只属于memcheck - 用
massif时忘记加--pages-as-heap=yes,导致只统计 malloc 分配,漏掉 mmap 分配的大块内存 - 在 CI 脚本里硬编码
--log-file=valgrind.log,但没清理旧文件,导致cachegrind把统计数据覆盖进去了,后续解析失败 - 对同一个程序连续跑
helgrind和memcheck,却没意识到线程调度差异可能导致问题在一种工具下复现、另一种下消失
真正关键的不是“怎么切”,而是“为什么切”——先明确你要回答的问题:是内存泄漏?还是 cache 不友好?还是线程死锁?答案决定了该用哪个工具,而不是反过来配参数凑效果。


















