服务器内存泄漏定位,ps、top
服务器内存持续上涨,通常不是凭空发生的,而是某个进程在长时间运行中不断申请内存却不释放。
本文用 ps、top、smem 三种工具,教你一步步定位内存持续上涨的进程,并给出验证方法,适合在 Linux 云服务器或物理机上直接跟着操作。
先分清楚:是真的内存泄漏,还只是缓存占用?
执行 free -h 查看整体内存。
如果 available 明显偏低,buff/cache 偏高,不一定就是泄漏,Linux 会尽量把空闲内存用作缓存。
判断泄漏的关键是:进程的常驻内存(RES)持续增长,而且增长趋势不回落。
所以排查第一步不是杀进程,而是先记录当前状态:
free -h
ps aux --sort=-%mem | head -20
记录下内存占用最高的几个进程名和 RES 数值,等 5 到 10 分钟后再看一次,若同样的进程 RES 明显变大,就进入下一步。
用 ps 快速排出内存占用 Top 进程
ps aux 是查看进程内存最直接的命令,按内存占用排序可以这样写:
ps aux --sort=-%mem | head -15
输出里第三列 %MEM 是物理内存占比,第四列 VSZ 是虚拟内存,第六列 RSS 是实际占用的物理内存。
重点关注 RSS 高的进程,比如 Java、Node.js、MySQL、PHP-FPM 都是常见泄漏对象。
一次排序只能看到当前瞬间,想看趋势可以用 watch 命令每隔几秒自动刷新:
watch -n 5 'ps aux --sort=-%mem | head -15'
如果某个进程始终排在前面,并且 RSS 数值每次都变大一点,就优先怀疑它。
用 top 实时观察内存变化趋势
top 能动态刷新进程资源占用,比 ps 更适合观察变化。
在终端执行:
top
进入界面后按 Shift+M 可以按内存使用率排序,再按 c 显示完整命令行。
想只看某个进程的实时变化,可以先用 pgrep 拿到 PID,再执行:
top -p PID
这里的 PID 替换成你怀疑的进程号。
在 top 界面里,RES 列就是常驻内存,数值持续上升而不回落,基本可以确认内存存在问题。
按 q 退出。
用 smem 找出真实物理内存占用大户
ps 和 top 显示的 RSS 包含共享内存,可能高估进程实际占用。smem 能按 USS(Unique Set Size,独占物理内存)排序,更适合判断谁在真正吃掉内存。
如果系统没装,Debian/Ubuntu 执行:
apt update && apt install smem -y
CentOS/RHEL 可用:
yum install epel-release -y && yum install smem -y
然后按 USS 排序查看:
smem -k -s uss | head -20
输出会列出 PID、User、Command、USS、PSS、RSS。
其中 USS 是该进程独享的内存,PSS 是按共享比例分摊后的内存,两者都比 RSS 更能反映“谁占得多”。
定位到可疑进程后,再用 systemctl status PID 或 ls -l /proc/PID/cwd 确认它属于哪个服务。
避坑:这几点最容易误判
第一,不要把 VSZ 当成实际内存。 VSZ 是虚拟内存,可能远超物理内存,不代表真实占用,判断泄漏以 RSS 和 USS 为准。
第二,缓存增长不等于泄漏。 如果 buff/cache 占了很多,但进程 RSS 稳定,通常只是文件读写缓存,系统会在内存紧张时自动释放,不需要处理。
第三,短时间观察可能看不出问题。 有些泄漏是慢慢上升的,建议至少记录 3 次数据,间隔 10 到 15 分钟,或者用脚本连续记录:
for i in {1..6}; do ps -o pid,rss,comm -p PID; sleep 300; done
这样能看到 RSS 是否呈单调递增。
验证:确认泄漏后怎么继续查
如果确定某个进程内存持续上涨,先重启该服务临时恢复,再根据进程类型深挖。
比如 Java 应用可以用 jmap -heap PID 看堆内存,Node.js 可以开启 --inspect 抓取堆快照;
PHP-FPM 则检查 pm.max_requests 是否设置过小。
最后补一句:很多云服务器控制台也自带内存监控图,把监控周期缩短到 1 分钟,能辅助你交叉确认内存上涨的起始时间。
按本文步骤做完,你就能从整体面板和进程两个维度准确定位内存泄漏源,而不是盲目重启服务器。