关于 valgrind
为 Agent 提供使用 Valgrind 检测内存错误及分析缓存、调用图和堆用量的指南,包含 Memcheck 报告解读、抑制规则和命令示例。
主要功能
- 01Memcheck 内存错误检测
- 02泄漏与未初始化值分析
- 03Cachegrind 缓存模拟
- 04Callgrind 调用图分析
- 05Massif 堆用量分析
适用场景
- 01排查内存泄漏或无效访问
- 02不使用 perf 时分析缓存行为
- 03查找调用开销与堆峰值位置
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ mohitmishra786/ low-level-dev-skills --skill valgrind安装后在 Claude Code 中输入/valgrind确认已加载。
附带文件references/valgrind-vs-asan.md
详细介绍
Valgrind
用途
引导 Agent 使用 Valgrind 工具:使用 Memcheck 检测内存错误,使用 Cachegrind 模拟缓存,使用 Callgrind 生成调用图,并使用 Massif 分析堆内存。
触发条件
- “我的程序有内存泄漏/释放后使用问题”
- “我不能使用 ASan,可以改用 Valgrind 吗?”
- “不使用 perf,如何分析缓存行为?”
- “如何使用 Callgrind 可视化调用图?”
- “如何分析堆内存分配模式?”
- “Valgrind 报告了第三方代码中的错误,但我无法修复”
工作流
1. Memcheck — 内存错误检测
使用 -g -O1 编译以获得最佳结果。-O0 也可以;避免使用 -O2 或更高优化级别,否则可能产生误报。
valgrind --tool=memcheck \
--leak-check=full \
--show-leak-kinds=all \
--track-origins=yes \
--error-exitcode=1 \
./prog [args]
主要标志:
| 标志 | 默认值 | 作用 |
|---|---|---|
--leak-check=full | summary | 显示完整的泄漏详情 |
--show-leak-kinds=all | definite | 显示所有类型的泄漏 |
--track-origins=yes | no | 显示未初始化值的来源(速度较慢) |
--error-exitcode=N | 0 | 如果发现错误,则以 N 退出(用于 CI 集成) |
--log-file=file | stderr | 将报告保存到文件 |
--suppressions=file | none | 忽略已知的误报 |
--gen-suppressions=yes | no | 打印错误对应的抑制指令 |
--max-stackframe=N | 2000000 | 为较深的调用栈增大限制 |
--malloc-fill=0xAB | off | 填充已分配的内存(检测未初始化值的使用) |
--free-fill=0xCD | off | 填充已释放的内存(检测释放后使用) |
2. 理解 Memcheck 输出
==12345== Invalid read of size 4
==12345== at 0x4007A2: foo (main.c:15)
==12345== by 0x400846: main (main.c:30)
==12345== Address 0x5204040 is 0 bytes after a block of size 40 alloc'd
==12345== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck.so)
==12345== by 0x40074B: main (main.c:25)
- 无效读取/写入:越界访问;检查数组边界
- 使用未初始化的值:先读后写;使用
--track-origins=yes - 无效释放/重复释放:
malloc/free不匹配;检查所有权 - 确定丢失:没有指针指向该内存块;属于明确的泄漏
- 间接丢失:通过一连串内存块丢失;通常表示存在一个根泄漏
- 可能丢失:指针可能指向内存块的中间位置;使用自定义分配器时通常是误报
3. 泄漏类型
| 类型 | 含义 |
|---|---|
| 确定丢失 | 没有指针指向该内存块 |
| 间接丢失 | 通过另一个已丢失的内存块丢失 |
| 可能丢失 | 指针指向内存块的中间位置 |
| 仍可访问 | 程序退出时仍有指针指向该内存块;不算泄漏,但从未释放 |
对于库代码,使用 --show-leak-kinds=definite,indirect 可以减少仍可访问内存造成的干扰。
4. 抑制规则
# Generate suppression for current error
valgrind --gen-suppressions=yes ./prog 2>&1 | grep -A20 '{'
# Example suppression file (valgrind.supp)
{
openssl_uninit
Memcheck:Cond
fun:SHA256_Init
...
}
# Use suppression file
valgrind --suppressions=valgrind.supp ./prog
5. Cachegrind — 缓存模拟
valgrind --tool=cachegrind ./prog
# Output: cachegrind.out.PID
# Annotate source
cg_annotate cachegrind.out.12345 --auto=yes
# Diff two runs
cg_diff cachegrind.out.before cachegrind.out.after
主要指标:
I1mr/ILmr:L1/末级指令缓存未命中率D1mr/DLmr:L1/末级数据读取未命中率D1mw/DLmw:L1/末级数据写入未命中率
6. Callgrind — 调用图分析
valgrind --tool=callgrind --callgrind-out-file=callgrind.out ./prog
# Analyse
callgrind_annotate callgrind.out
# Visualise in KCachegrind (GUI)
kcachegrind callgrind.out
Callgrind 的运行速度比 perf 慢,但无需 root 权限,并且能提供精确的调用次数。
7. Massif — 堆内存分析
valgrind --tool=massif ./prog
# Visualise
ms_print massif.out.PID | less
# GUI
massif-visualizer massif.out.PID
Massif 会显示堆内存用量随时间的变化;可用于查找内存分配峰值位置并追踪逐渐累积的泄漏。
8. 性能注意事项
Valgrind Memcheck 的运行速度约为原生程序的 1/10 至 1/50。可通过以下方式缓解:
- 使用较短且具有代表性的工作负载
- 使用
--error-exitcode=1,在 CI 中发现错误后立即失败 - 在开发过程中使用 ASan(
-fsanitize=address)进行更快的内存检查 - 仅在无法使用 ASan 时(例如旧工具链或类似生产环境)使用 Valgrind
Valgrind 与 ASan 的比较请参阅 references/valgrind-vs-asan.md。
相关技能
- 使用
skills/runtimes/sanitizers获取更快的 ASan/UBSan 替代方案 - 使用
skills/profilers/linux-perf进行 CPU 级分析(速度比 Cachegrind 快) - 使用
skills/profilers/flamegraphs可视化 Callgrind 输出
评论
支持 Markdown