服务器内存过高排查流程
一、整机内存:先判断是不是真有问题
1. 看整体
free -h
| 指标 | 怎么看 |
|---|---|
| available | 最重要,表示还能给程序用的内存 |
| buff/cache | 文件缓存,可回收,不等于"被占死" |
| Swap | 若持续被大量使用,说明物理内存已经紧张 |
结论:
available还充足 → 可能只是缓存高,不必立刻处理available很低 + Swap 持续涨 → 需要继续往下查
2. 看全部进程占用(整机排查的核心一步)
ps aux --sort=-%mem | head -20
或实时刷新:
top
按 M:按内存排序
按 P:按 CPU 排序
按 q:退出
记录前几名的:PID、进程名、%MEM、RSS。
| 列 | 含义 |
|---|---|
| RSS | 实际物理内存(KB),最可靠 |
| %MEM | 占整机内存百分比 |
| VSZ | 虚拟内存,Java 等进程常很大,参考价值低 |
换算:RSS(MB) = RSS(KB) ÷ 1024
3. 整机排查流程
free -h
↓ 是否 really 紧张?
ps aux --sort=-%mem | head -20
↓ 找出占用最高的几个进程
ps -fp <PID> 确认进程是什么
↓
按类型分析(Java / 数据库 / Web / 未知)
↓
判断:正常负载 / 配置过大 / 泄漏 / 重复进程 / 异常进程
↓
处理 + 持续观察
确认某个 PID 是什么:
ps -fp <PID>
cat /proc/<PID>/cmdline | tr '\0' ' '
4.根据端口号查看对应pid
root@01 \~# ss -tlnp | grep 12510
LISTEN 0 100 :::12510 :::* users:(("java",pid=21119,fd=603))
root@01 \~# ss -tlnp | grep 12590
LISTEN 0 100 :::12590 :::* users:(("java",pid=22280,fd=602))
5.kill进程
kill -9 <PID>
二、单个进程内存过高:通用流程
原则:先看全部,再聚焦一个。
第 1 步:看全部进程占用情况
ps aux --sort=-%mem | head -20
确认:
- 该进程在排行榜第几名
- 是否多个同类进程叠加占用
- 是否还有其它进程占更大头
第 2 步:聚焦目标进程
ps -p <PID> -o pid,user,rss,vsz,%mem,%cpu,etime,cmd
| 字段 | 用途 |
|---|---|
| rss | 当前实际占用 |
| etime | 运行了多久 |
| %cpu | 是否伴随 CPU 异常 |
第 3 步:判断"正常高"还是"异常高"
| 现象 | 可能原因 |
|---|---|
| 一启动就很高,之后稳定 | 启动参数或默认配置预留了较多内存 |
| 业务高峰时升高,过后回落 | 正常负载波动 |
| 持续缓慢上涨,长期不回落 | 内存泄漏嫌疑 |
| 同类进程有多个 | 重复启动、未停旧进程 |
| 进程在但服务不可用 | 失败残留进程 |
第 4 步:按进程类型继续查
Java 进程
是否 OOM / GC 问题
grep -i "OutOfMemory\|GC overhead\|Metaspace" /path/to/app.log
有 JDK 时看 GC
jstat -gc <PID> 2000 10
jmap -heap <PID>
关注:堆、Metaspace、Full GC 后内存是否下降。
数据库(MySQL / PostgreSQL 等)
ps -fp <PID>
MySQL 示例
mysql -e "SHOW VARIABLES LIKE '%buffer%';"
mysql -e "SHOW PROCESSLIST;"
常见:缓冲池、连接数、大查询。
Redis
redis-cli info memory
关注:used_memory、是否达到 maxmemory。
Nginx / 其它
ps -fp <PID>
ls -l /proc/<PID>/exe
看 worker 数量、是否异常 fork。
第 5 步:看系统对该进程的限制与详情
进程详细内存分布(Linux)
cat /proc/<PID>/status | grep -E 'VmRSS|VmSize|Threads'
打开的文件、连接数(辅助判断泄漏)
ls /proc/<PID>/fd | wc -l
ss -tp | grep <PID>
第 6 步:处理思路(通用)
| 情况 | 处理 |
|---|---|
| 重复进程 | 只保留有效实例,停掉其余 |
| 配置过大 | 调小内存相关配置(JVM、DB buffer 等) |
| 临时高峰 | 观察,必要时扩容或限流 |
| 疑似泄漏 | 重启缓解 + 抓 dump/日志 + 修代码 |
| 未知进程 | 确认来源,不应存在则停掉并排查入侵 |
第 7 步:处理后验证
free -h
ps aux --sort=-%mem | head -20
ps -p <PID> -o pid,rss,%mem,etime
持续观察一段时间,确认是否再次上涨。
三、一张总流程图
内存告警
↓
free -h(看 available / swap)
↓
ps aux --sort=-%mem | head -20(看全部进程)
↓
锁定 1~3 个可疑 PID
↓
ps -fp PID(确认是什么程序)
↓
分支排查
├─ Java → 日志 / jstat / GC / dump
├─ DB → 缓冲池 / 连接 / 慢 SQL
├─ Redis → info memory
└─ 其它 → 路径 / 配置 / 是否重复
↓
处理 → 再跑 free + ps 验证
四、常用命令速查
整机
free -h
全部进程按内存排序
ps aux --sort=-%mem | head -20
单个进程
ps -p <PID> -o pid,rss,vsz,%mem,%cpu,etime,cmd
实时
top
进程详情
ps -fp <PID>
cat /proc/<PID>/status | grep Vm
核心习惯:查单个进程之前,先用 ps aux --sort=-%mem 看全局排行,避免只盯一个进程、忽略真正的大头。