
你的服务器内存使用率一直在涨。周一30%,周二40%,周五80%。你重启了一下,回到30%。下周又重复一遍。
你知道有内存泄漏,但不知道哪个进程在泄漏。今天讲一套排查方法,帮你找到元凶。
先看一个数据
内存泄漏是服务器常见问题之一。在排查过程中,通过观察内存使用趋势、检查/proc/meminfo和进程内存映射,可以逐步定位泄漏源。开发环境中的内存泄漏通常比生产环境更容易定位,因为你有更多工具可用。
第一步:确认是内存泄漏,不是正常增长
先区分“内存泄漏”和“正常缓存增长”。
用free -h查看内存分布:
text
total used free shared buff/cache available Mem: 7.6G 2.1G 1.2G 150M 4.3G 5.0G
used:进程实际占用的内存buff/cache:系统缓存(可以回收,不是泄漏)available:真正可用的内存
如果used持续增长,而buff/cache变化不大,可能是内存泄漏。如果只是buff/cache增长,是正常的缓存行为,系统会在内存紧张时自动回收。
查看内存趋势:
bash
# 查看过去几天的内存变化 sar -r
如果安装了sysstat,sar -r会显示每天的内存使用记录。观察趋势,持续上升通常需要关注。
第二步:用top定位高内存进程
bash
top -o %MEM
-o %MEM按内存使用率排序,最耗内存的进程在最上面。
关注:
%MEM超过10%的进程RES(常驻内存)持续增长的进程VIRT(虚拟内存)异常高的进程
记录PID,进入下一步。
第三步:追踪进程的内存变化
用ps查看单个进程的内存变化:
bash
# 查看某个进程的VSZ(虚拟内存)和RSS(常驻内存) ps -p PID -o vsz,rss,comm
多次运行,观察RSS是否持续增长。RSS持续上升而业务量没有增加,基本可以确认该进程有内存泄漏。
用pmap查看进程的内存映射:
bash
pmap -x PID
输出会显示进程占用的所有内存区域,以及各区域的权限和大小。如果看到大量[anon]匿名内存块,可能是程序申请了内存但未释放。
第四步:查看/proc/meminfo分析系统内存
bash
cat /proc/meminfo
关键字段解读:
| 字段 | 含义 |
|---|---|
MemTotal | 总内存 |
MemFree | 空闲内存 |
MemAvailable | 真正可用内存 |
Buffers | 块设备缓存 |
Cached | 文件系统缓存 |
Slab | 内核数据结构缓存 |
SReclaimable | 可回收的内核内存 |
SUnreclaim | 不可回收的内核内存(持续增长可能是内核泄漏) |
如果SUnreclaim持续增长,可能是内核内存泄漏。
第五步:检查Java/Python应用的堆内存
Java应用:
bash
# 查看Java堆内存使用 jstat -gc PID
关注OGC(老年代GC次数)和OU(老年代使用量)。如果OU持续增长而OGC没有相应增加,说明老年代存在内存泄漏。
bash
# 查看堆内存配置 jcmd PID VM.flags | grep -E "Xms|Xmx"
Python应用:
Python的内存管理相对简单,但某些情况下(如循环引用或第三方C扩展未正确管理内存)仍会导致泄漏。用tracemalloc模块或在开发环境使用memory-profiler可以帮助定位。
第六步:检查是否因为文件句柄未关闭
有时内存泄漏是资源泄漏的副产物。程序打开了文件但没关闭,可能间接导致内存持续增长。
bash
# 查看进程打开的文件数 lsof -p PID | wc -l
持续增长说明资源泄漏。
排查顺序总结
- 确认是泄漏不是缓存:
free -h看used,不是buff/cache - 找高内存进程:
top -o %MEM - 追踪单个进程:
ps -p PID -o vsz,rss多次观察 - 看内核内存:
cat /proc/meminfo看SUnreclaim - 看堆内存:Java用
jstat,Python用tracemalloc - 查资源泄漏:
lsof -p PID | wc -l
真实案例
一台Java应用服务器内存持续增长,每周重启一次。top发现一个Java进程占用6GB内存,jstat显示老年代使用量不断上升,但GC回收量很小。分析堆转储后发现是某个缓存类没有设置过期时间,缓存对象持续积累。调整缓存配置后,内存稳定在4GB。
最后一句
内存泄漏排查的关键是区分:是正常缓存增长,还是进程内存泄漏,还是内核内存问题。
先用free -h排除缓存干扰,再用top找到嫌疑进程,然后用ps追踪进程的持续增长趋势。如果进程内存稳定但系统内存持续增长,检查/proc/meminfo的SUnreclaim。泄漏一定有痕迹,只是看你有没有找到对的工具。




