默认参数不够用,Memcheck 默认仅检测可访问性错误且不报告内存泄漏,必须添加 --leak-check=full 和 --show-leak-kinds=all 才能全面发现泄漏问题。

valgrind --tool=memcheck 默认参数够用吗
够用,但默认只报告错误不显示堆栈,容易找不到问题源头。第一次运行必须加 --leak-check=full 和 --show-leak-kinds=all,否则内存泄漏会直接被忽略——memcheck 默认只检查「可访问性错误」(比如越界读写),不主动扫描泄漏。
常见误操作是只跑 valgrind ./a.out,结果没报错就以为没问题,其实泄漏全被静默跳过了。
-
--leak-check=full:开启详细泄漏分析(含调用栈) -
--show-leak-kinds=all:显示 definitely、possibly、still reachable 三类泄漏 -
--track-origins=yes:遇到无效读写时定位未初始化内存来源(调试Invalid read of size X必开) - 避免加
--suppressions=...或--gen-suppressions=yes——第一次用先看原生输出,压制文件会掩盖真实问题
程序带参数或需要环境变量怎么传
valgrind 命令本身不解析你的程序参数,所有 ./a.out 后面的内容都会原样传给被测程序。环境变量要用 env 或 VALGRIND_OPTS 配合,别用 export 后直接跟 valgrind——那只会污染当前 shell 环境,不影响 valgrind 子进程。
正确写法:
valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all ./myapp arg1 arg2
要带环境变量:
LD_LIBRARY_PATH=./lib valgrind --tool=memcheck ./myapp
- 不能写成
export LD_LIBRARY_PATH=... && valgrind ./myapp——valgrind 启动的子进程不会继承父 shell 的 export 变量(除非显式传递) - 如果程序依赖
HOME或PATH,也得同样前置设置,或用env VAR=val valgrind ... - 注意:valgrind 会重定向
stdout/stderr,程序里用printf打的日志可能延迟出现或混在 valgrind 输出里,加--log-file=valgrind-out.txt更清晰
看到 “Invalid write of size 4” 怎么快速定位
这个错误表示往非法地址写了 4 字节(通常是 int 或指针),但默认输出只显示出错时的栈帧,不显示分配位置。必须配合 --track-origins=yes 才能追溯到哪行 malloc/new 分配了这块内存,以及是否被提前 free。
典型场景:
- 数组下标越界(
a[10]访问长度为 10 的数组 → 实际索引 0~9) - 释放后使用(
free(p); p[0] = 1;) - 栈变量地址逃逸(返回局部数组地址,后续写入)
关键点:
- 不加
--track-origins=yes时,valgrind 只说「你在 0x... 写了」,不说「这地址从哪来」 - 加了之后,会多一段
by 0x...: foo (foo.c:12)+allocated at ...,这才是真正有用的线索 - 性能代价明显(慢 2–3 倍),但第一次排查必须开
为什么跑完没输出、卡住、或报 “Cannot allocate memory”
不是程序卡死,是 valgrind 自身内存开销太大——它会复制整个进程的内存镜像做跟踪,对大程序(尤其带大量 malloc 或 mmap)极易触发系统限制。
- 先试
--max-stackframe=8000000(单位字节),防止因栈帧过大被拒(常见于递归深或局部数组大) - 若报
Cannot allocate memory,大概率是mmap失败,加--pages-as-bits=...减少位图内存占用(但会降低精度,仅临时调试用) - 确保程序没调用
fork()后父子进程都继续跑重负载——valgrind 对 fork 支持有限,子进程可能无法正常检测 - Linux 上检查
/proc/sys/vm/max_map_count,太小(如默认 65530)会导致 mmap 失败,临时加大:sudo sysctl -w vm.max_map_count=262144
第一次用别碰复杂选项,先让命令跑通、有输出,再逐步加参数收窄问题。漏掉 --leak-check=full 或 --track-origins=yes 是最常被忽略的两个开关。


















