如何查找C++程序中的“弱”内存泄漏
Linux平台调试方案
1. 专用内存分析工具
- massif(valgrind组件):valgrind自带的massif工具专门用于堆内存趋势分析,不会仅检查程序退出时的内存泄漏,会完整记录运行全周期的内存分配状态,支持导出不同时间点带调用栈的内存快照。运行命令为
valgrind --tool=massif --time-unit=ms 你的程序路径,运行结束后生成massif.out.前缀的结果文件,执行ms_print massif.out.xxx即可查看内存峰值对应的分配调用栈、最大对象的分配位置,也可对比不同时间点的分配差异,直接定位持续增长的对象。 - AddressSanitizer 运行时快照:ASAN默认仅在程序退出时做泄漏检查,你可以通过插桩手动触发快照:在代码中引入
<sanitizer/asan_interface.h>,在需要采集状态的位置调用__lsan_do_leak_check(),此时ASAN会将当前所有未释放的内存当作泄漏输出,携带完整调用栈。你可以在程序运行的不同阶段触发该接口,对比两次输出的差异即可定位持续累积的对象。如果不想修改代码,可配置环境变量LSAN_OPTIONS=max_leaks=10000:fast_unwind_on_malloc=0,配合gdb在运行时断点触发__lsan_do_leak_check()即可。 - gperftools heap profiler:谷歌推出的轻量堆分析工具,性能开销远低于valgrind,适合带生产负载运行。启动时配置环境变量
HEAPPROFILE=/tmp/heap.hprof 你的程序路径,工具会自动按时间、内存增长阈值生成快照文件,执行pprof --text 你的程序路径 /tmp/heap.hprof.0001.heap即可查看每个调用栈的分配内存大小,执行pprof --base 旧快照路径 新快照路径可直接对比两次快照的内存增长部分,快速定位持续分配未释放的代码路径,也支持按对象大小排序查找最大分配点。
2. 无插桩在线调试工具
- bpftrace 动态追踪:针对不能重启插桩的在线运行进程,可通过bpftrace动态hook malloc/free接口,统计每个调用栈的存活内存总大小,性能开销极低,适合生产环境临时排查。
- procfs + gdb 联合分析:先通过
/proc/[进程pid]/smaps找到占用内存最大的匿名映射段,再用gdb attach到运行中的进程,dump对应内存段的内容,结合符号信息反推对象类型,适合无提前编译插桩的排查场景。
其他平台方案
- Windows平台可使用UMDH(User-Mode Dump Heap)工具,属于Windows官方调试工具集,支持抓取不同时间点的堆快照,对比快照差异即可找到持续增长的分配调用栈。
- macOS平台可使用Xcode自带的Leaks工具「增长分析」模式,或Instruments的Allocations模板,记录全运行周期的内存分配,过滤已释放对象后即可查看累积对象和对应调用栈。
通用调试思路
- 优先抓取内存峰值的分配快照,按分配大小排序,优先排查占比最高的几个调用栈
- 采集两个间隔较长的运行时间点的内存快照,对比排除临时分配对象,剩余的持续存在的分配即为累积资源
- 针对缓存类场景可补充统计埋点,输出当前缓存的元素数量、总占用内存,配合分配栈信息确认是否是缓存淘汰逻辑异常导致的无上限增长。
内容的提问来源于stack exchange,提问作者Vincent Fourmond
相关产品推荐
相关产品推荐

