Valgrind 不适合直接用于压力测试,因其内存暴涨、卡死是自身限制所致;应改用快照式检测:先 summary 判趋势,再 full 模式精确定位,结合代码逻辑排除误判。

Valgrind 跑压力测试时内存暴涨就卡死?别硬扛
Valgrind 本身不是为高吞吐、长时间运行的压力测试设计的。直接把 valgrind --leak-check=full 套在压测脚本里,大概率会:进程卡住、内存爆到几十 GB、跑几个请求就 OOM —— 这不是你程序漏得多,是 Valgrind 自己扛不住。
压测前必须加的三个编译和启动参数
不改编译和启动方式,压测中 Valgrind 的输出基本不可信。重点不在“能不能跑”,而在“跑出来的泄漏是不是真问题”:
-
-g必须加:否则valgrind只能显示汇编地址,没法定位到new或malloc的具体行号 -
-O0必须加:优化(尤其是-O2)会让内联、循环展开、变量复用打乱堆栈,valgrind报的调用栈可能指向完全无关的函数 -
--vgdb=no显式关闭:压测中不需要实时调试支持,开它反而增加通信开销和不确定性
怎么让 Valgrind 在压测中“活下来”并抓到关键泄漏
核心思路:不追求全程监控,而是用“快照 + 定点复现”代替“全量扫描”。真实泄漏往往在连接建立/释放、缓存初始化/淘汰等固定路径上发生,而非随机分布:
- 用
--tool=memcheck --leak-check=summary先跑 10–20 次请求:只看结尾的HEAP SUMMARY,确认是否有稳定增长趋势(比如每次多 8KB) - 发现增长后,立刻切到
--leak-check=full --show-leak-kinds=all --num-callers=20,只跑 1–3 次请求:拿到完整调用栈,重点看definitely lost和indirectly lost的块是否集中在某几个函数(如accept_connection、create_session) - 对可疑函数单独写最小复现 case:剥离网络、线程、日志等干扰,只保留内存分配逻辑,再用
valgrind精准验证
常见误判:压测中看到“reachable”就以为没泄漏?
reachable 内存只是“程序退出时仍有指针能访问到”,不代表安全。在长连接服务或线程池场景下,它极可能是:
- 全局缓存表(如
std::map<int std::shared_ptr>></int>)不断插入但没清理 - 线程局部存储(
thread_local)里的对象未被析构(尤其 C++11 后 TLS 析构顺序不可靠) - 信号处理函数中分配的内存,因信号异步到达,导致清理逻辑被跳过
这类问题 valgrind 不报 definitely lost,但压测跑几小时后 RSS 持续上涨——必须结合 pstack、/proc/<pid>/maps</pid> 和代码逻辑交叉判断。
真正难的从来不是跑出泄漏报告,而是从 valgrind 输出里区分:是压测工具本身没关连接导致的假阳性,还是你的对象工厂忘了调 delete;是第三方库内部缓存策略,还是你调用它时传错了生命周期标志。这些没法靠参数自动解决,得盯住 at 0x...: your_function (your_file.cpp:123) 这一行,一行行翻源码。


















