valgrind无法attach到运行中进程检测内存泄漏,必须从启动时介入;应使用--leak-check=full --show-leak-kinds=all --track-origins=yes重跑程序,结合/proc/pid/maps、malloc_stats()、asan及语言特有工具(如python的gc、node.js的devtools)综合诊断。

用 valgrind --leak-check=full 检测运行中进程的内存泄漏
直接 attach 到已有进程不可行——valgrind 必须从程序启动时介入,否则无法监控 malloc/free 调用链。所以得重跑目标程序:
valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes ./my_program arg1 arg2。关键参数里
--track-origins=yes 能定位未初始化内存的来源,对“间接泄漏”(比如指针拷贝后丢失原始地址)很有用;--show-leak-kinds=all 会区分 definitely lost、indirectly lost 等类型,别只盯着第一行 summary。
gdb + /proc/[pid]/maps 和 malloc_stats() 辅助判断异常增长
如果程序已长期运行且疑似泄漏,先看 RSS 是否持续上涨:ps -o pid,rss,comm -p [pid] 隔 30 秒跑两次对比。再进 /proc/[pid]/maps 查堆区(标有 [heap] 的行)大小是否扩大;若扩大但 gdb 里执行 call malloc_stats() 显示已分配字节数没变,大概率是 mmap 分配未释放(比如某些日志库或 jemalloc 的 arena 扩张),不是传统 malloc 泄漏。
- 注意
malloc_stats()只对 glibc 生效,musl 或自定义分配器不响应 -
/proc/[pid]/smaps里的Anonymous和MMUPageSize字段能帮你区分是大页还是普通页泄漏
用 asan 编译 + 运行捕获释放后使用和越界——常被误认为泄漏
很多“内存持续增长”实际是 use-after-free 或缓冲区溢出导致的堆损坏,进而让后续 malloc 失败或行为异常。这时 valgrind 可能报一堆无关错误,不如换地址消毒器:
gcc -fsanitize=address -g my_program.c -o my_program。运行时报错位置极精准,且附带堆栈和内存映射快照。但注意:
- ASan 会显著拖慢速度(5–10 倍),不适合高吞吐服务实机压测
- 必须用 ASan 编译的二进制,不能对现成 binary 注入
- 报
heap-use-after-free时,泄漏本身可能只是表象,根源在提前释放
Python/Node.js 等动态语言别硬套 C 工具——优先查引用计数和事件循环
对 python 进程,valgrind 会淹没在解释器内部调用里,真正有效的是:import gc; gc.set_debug(gc.DEBUG_STATS) 开启统计,或用 objgraph 绘制对象引用图;node 则用 node --inspect 启动后 Chrome DevTools 的 Memory 面板拍堆快照比对。这类环境里,“泄漏”往往源于闭包持有了不该持有的大对象、事件监听器未 remove、或定时器未 clear——工具只是辅助,得结合代码逻辑看生命周期。
真实场景里,泄漏常藏在第三方库的异步回调、信号处理函数或 fork 后的子进程资源继承中;valgrind 报的 still reachable 很多是库的缓存设计,不是 bug。动手前先确认:RSS 增长是否稳定、是否复现于最小可运行路径、有没有忽略 setrlimit 导致的 OOM 杀死伪装成泄漏。









