linux 内存泄漏怎么排查/定位(附工具)
答案:先用 free/smem/top 确认内存持续下降并找到增长进程,再用 valgrind 或 ASan 定位泄漏点;生产环境用 mtrace、/proc/PID/status 的 VmRSS 观察趋势。
一、排查三步走
# 1. 确认趋势(内存是否持续下降)
free -h # used 持续上升、available 下降
watch -n 5 free -h # 每 5 秒观察
# 2. 找增长进程(RSS 持续变大)
top # 按 M 按内存排序
watch -n 1 'ps -eo pid,rss,comm --sort=-rss | head' # 看 RSS 变化
cat /proc/<PID>/status | grep VmRSS # 精确实时值,隔几分钟再看
# 3. 定位泄漏点(编译期检测)
valgrind --leak-check=full --show-leak-kinds=all ./program二、定位工具对比
| 工具 | 原理 | 适用 |
|---|---|---|
| valgrind | 虚拟化执行,精确跟踪每次 malloc/free | 开发期,慢但准 |
| ASan | 编译插桩,快速 | 开发/CI,速度快 |
| mtrace | glibc 钩子,记录调用栈 | 无需重编,运行期 |
| heaptrack / Massif | 堆快照分析 | 复杂泄漏/峰值分析 |
| smem | 按共享内存统计 RSS | 多进程共享内存场景 |
| /proc/PID/status | VmRSS 实时值 | 生产无侵入观察 |
三、valgrind 用法(精确但慢)
valgrind --leak-check=full --show-leak-kinds=all ./program输出分类:
- definitely lost:明确泄漏(指针丢失);
- indirectly lost:依赖泄漏对象的子块;
- possibly lost:可疑(可能还有指针);
- still reachable:未释放但指针还在(程序退出前没 free,通常不算泄漏)。
四、ASan 用法(快)
gcc -fsanitize=address -g prog.c -o prog && ./prog
# 泄漏时输出:
# ERROR: LeakSanitizer: detected memory leaks
# 带分配调用栈,可直接定位五、常见坑
free的 used 高不代表泄漏:Linux 会用空闲内存做 page cache,看available而不是used;- valgrind 慢 10~50 倍:别在生产跑,只在复现场景用;
- RSS 上升有瞬时假象:glibc 不立刻归还内存(内存池),持续观察趋势而非单点;
- 泄漏最终 = OOM:泄漏到极限会被 OOM Killer 杀掉,参考内存溢出排查。
深度入口
- valgrind 完整指南:valgrind
- ASan/TSan 使用:ASan 内存检测
- 内存统计口径:free 命令详解、smem
- 与 OOM 的关系:内存溢出(OOM)排查
FAQ
Q: linux 内存泄漏怎么排查? A: 三步:free/smem 确认趋势 → top/ps 找增长进程 → valgrind/ASan 定位泄漏点;生产用 /proc/PID/status 的 VmRSS 观察。
Q: linux 内存泄漏检测工具有哪些? A: valgrind、ASan、mtrace、libmemleak、heaptrack/Massif、smem。
Q: 怎么用 valgrind 检测内存泄漏? A: valgrind --leak-check=full --show-leak-kinds=all ./program,看 definitely/possibly lost 调用栈。
Q: ASan 怎么检测内存泄漏? A: 编译加 -fsanitize=address -g,运行后泄漏地址打印分配栈。
Q: 怎么在服务器上观察哪个进程内存涨? A: top 按 M 排序、watch ps -eo pid,rss,comm --sort=-rss、/proc/PID/status 的 VmRSS。
Q: 内存泄漏和内存溢出(OOM)区别? A: 泄漏是只分配不释放;溢出是一次性分配超限被 OOM Killer 杀。泄漏是过程、OOM 是结果。
一句话总结:内存泄漏排查 = free/top 找增长进程 + valgrind/ASan 定位泄漏点 + /proc/PID/status 做生产无侵入观察;看 available 别被 page cache 的 used 骗了,泄漏拖久了就是 OOM。