确认进程内存泄漏需先观察RSS是否无业务变化下持续线性上涨、重启后是否归零并重复爬升、Private_Dirty是否同步增长;仅VIRT大或free -h中used升高通常不是泄漏。

怎么确认进程正在泄漏内存(先别急着看日志)
直接翻日志前,得先确认是不是真泄漏——很多“RSS上涨”只是缓存预热、JVM堆增长或mmap文件读取导致的正常行为。关键看三点:RSS是否在无业务变化前提下持续线性上涨;重启后是否归零再以相似斜率爬升;Private_Dirty(来自 /proc/[PID]/smaps)是否同步增长。如果只是VIRT大或free -h里used升高,大概率不是泄漏。
valgrind生成的泄漏日志怎么看(C/C++程序适用)
valgrind --leak-check=full --show-leak-kinds=all ./your_program跑完后,输出里真正要盯的是definitely lost段。它会列出每块未释放内存的大小、分配位置(源文件+行号)、以及完整调用栈。注意:possibly lost不一定真漏,常是悬空指针;still reachable是程序退出时仍被持有的内存(比如全局缓存),不等于泄漏。日志里出现0 bytes in 0 blocks说明没检测到泄漏,别误判。
- 必须用带
-g编译的二进制,否则行号全丢 - 不能用
kill -9终止进程,得发SIGTERM让valgrind捕获退出路径 - 服务类进程建议加
--log-file=valgrind.log重定向,避免终端刷屏丢失信息
mtrace日志怎么解析(只对malloc/free有效)
运行前设好export MALLOC_TRACE=./mtrace.log,代码里调用mtrace()和muntrace(),结束后生成的日志是纯文本。格式形如:+ 0x7f8fb5397000 0x1000 @ ./test:[0x400624],其中+是malloc,-是free,地址后数字是字节数。= End之后若还有+没配对的行,就是泄漏点。用addr2line -e ./test 0x400624能把机器码地址转成源码行。
-
mtrace只跟踪glibc的malloc/free,不覆盖mmap或C++的new - 日志里地址是虚拟地址,需配合符号表才能定位,没
-g编译就只能靠上下文猜 - 多线程程序慎用,
mtrace本身非线程安全,可能漏记录
为什么/proc/[PID]/smaps里的Private_Dirty比RSS更准
RSS包含共享库页(比如多个进程共用libc),而Private_Dirty是进程独占且已修改的物理页,排除了共享干扰。泄漏一定反映在Private_Dirty上,但RSS可能因其他进程加载相同so而虚高。执行grep -i "private_dirty" /proc/[PID]/smaps | awk '{sum += $2} END {print sum}'可累加总值,每小时抓一次对比趋势比单看ps aux的RSS可靠得多。
-
Private_Clean一般不涨,涨了多半是mmap映射了只读文件并做了madvise -
Pss虽更公平(按共享比例折算),但计算开销大,不适合高频采样 - 别依赖
MemAvailable下降来反推泄漏——它受pagecache、slab等影响太大
valgrind日志和mtrace日志都只对用户态代码有效,内核模块泄漏得靠kmemleak或slabtop。而/proc/[PID]/smaps是唯一能实时、无侵入、跨语言验证泄漏存在的依据——哪怕你用Go或Java,只要Private_Dirty稳升,就得查代码。


















