属于大家的
VPS知识分享站

云服务器内存占用高:OOM、swap 与泄漏排查清单

先说结论:内存占用高不一定是故障,Linux 会把空闲内存拿去做缓存;真正要盯的是 available、swap 读写和 OOM。先分清“缓存占着”还是“进程真的漏了”,再决定重启、调配置还是加内存。

三个数先看明白:

  • free:完全没用的内存,通常很小,正常
  • available:应用还能拿到的内存,这个才是关键
  • buff/cache:缓存,可回收,不要看到它高就慌

如果 available 还充足、swap 没有持续读写,内存“看起来高”通常不是问题。反过来,available 很低、si/so 持续非 0、dmesg 有 OOM,才是真问题。

第一步:看整体内存

free -m
vmstat 1 5
# 看 si/so 是否持续非 0
cat /proc/meminfo | grep -E 'MemAvailable|SwapTotal|SwapFree|Dirty'

MemAvailable 是内核估算的可用内存,比 free 更有参考价值。buff/cache 高但 available 正常,说明缓存在干活,不需要处理。

第二步:找进程

ps aux --sort=-rss | head -20
top -o %MEM
smem -r -k 2>/dev/null | head -20

重点看 RSS 和增长趋势。PHP-FPM、MySQL、Java、Node、Redis 是常见的内存大户。把每个进程的实际占用和配置对上:FPM 的 pm.max_children、MySQL 的 buffer pool、Java 的 -Xmx、Redis 的 maxmemory。

内存罐向 swap 容器排水,带 OOM 警告光
available 低、swap 持续读写、dmesg 有 OOM,才是真问题。

第三步:判断是不是泄漏

泄漏的典型特征是“重启后回落,跑一段时间又涨回去”。判断方法:

  1. 记录进程 RSS,每小时一次,画一条曲线
  2. 观察业务量没变时 RSS 是否持续上升
  3. 重启单个 worker,看内存是否明显回落
  4. Java 抓 heap dump,PHP/Node 看内存 profile

如果 RSS 随请求量波动、稳定在某个区间,多半是缓存或连接池,不是泄漏。

第四步:看 OOM 和 cgroup

dmesg | grep -i -E 'oom|killed process'
journalctl -k | grep -i oom
cat /sys/fs/cgroup/memory.max 2>/dev/null
cat /sys/fs/cgroup/memory.current 2>/dev/null

容器里被杀,常见原因是 cgroup 限制而不是宿主机没内存。看 memory.max 和 memory.current,再看 OOM 日志里的进程名和触发时的内存。

容器管道漏水,滴入内存池
业务量不变但 RSS 持续上涨,重启后回落,基本就是泄漏。

第五步:swap 要不要开

swap 不是洪水猛兽,但要看场景:

  • 数据库、Redis:尽量不开,或把 swappiness 调低,避免热数据被换出
  • Web/应用:可以开小一点,作为 OOM 前的缓冲
  • 容器:注意 cgroup 的 swap 限制,别让容器把宿主机拖死
sysctl vm.swappiness
# 临时调整
sysctl -w vm.swappiness=10

swap 只能续命,不能解决泄漏。si/so 持续很高,说明内存已经不够,性能也会明显下降。

第六步:常见原因

  1. PHP-FPM worker 太多:每个 worker 几十 MB,max_children 一调就爆
  2. MySQL buffer pool 过大:占了机器一半以上,系统和其他进程没空间
  3. Java 堆没限制:默认堆按物理内存比例走,容器里容易超
  4. Redis 没设 maxmemory:数据一直涨,最后被 OOM
  5. 应用泄漏:长连接、缓存、日志缓冲没清理
  6. 备份/导出任务:一次性把大文件读进内存

连接池和缓存也会推高内存。数据库连接池、Redis 客户端、HTTP 客户端连接池,每个连接都占内存;池子开太大,空闲连接也会把内存吃掉。按实际并发设上限,别用默认值。

容器里还要看 cgroup 的 memory.max 和 memory.current。宿主机内存很足,但容器限制设得小,一样会 OOM;反过来,容器没限制,一个进程泄漏就能把整台机器拖死。

另外,RSS 高不等于泄漏,虚拟内存(VSZ)高更不代表问题;看 RSS 和实际可用内存,别被 VSZ 吓到。

第七步:应急处理

  1. 先看 available 和 OOM,确认是不是真的要处理
  2. 重启单个 worker 或 FPM pool,不要直接 reboot
  3. 限流、降级非核心功能,减少内存分配
  4. 临时加 swap 或升配,争取时间
  5. 保留现场:RSS 曲线、OOM 日志、heap dump

第八步:长期优化

  • 按进程算内存预算:系统 + 应用 + 数据库 + 缓存 + 余量
  • 给容器设 memory limit 和 request,避免互相抢
  • FPM max_children、Java -Xmx、Redis maxmemory 都要显式配置
  • 监控 available、swap、OOM、进程 RSS 趋势
  • 修复泄漏,别用定时重启掩盖问题
带内存仪表的服务器被重新调整到合适规格
按系统、应用、数据库、缓存和余量做内存预算,别让容器互相抢。

常见问题 FAQ

Q1:内存占用 90% 一定要处理吗?

不一定。看 available 和 swap。缓存占着内存是正常的,available 充足就不用动。

Q2:怎么快速判断是不是泄漏?

业务量不变时 RSS 持续上升,重启后回落,基本就是泄漏。再用 heap dump 或 profile 确认。

Q3:OOM 是内存不够还是限制太紧?

看 dmesg 和 cgroup 限制。容器里常见是 memory.max 设得太小,不一定是宿主机没内存。

Q4:加内存能解决问题吗?

容量问题可以,泄漏问题只能推迟。先定位是配置、容量还是代码,再决定加不加。

Q5:swap 开了会不会更慢?

频繁换页会明显变慢。数据库和 Redis 尽量少用 swap,Web 应用可以留一点作为缓冲。

总结

内存排查的顺序是:看 available 和 swap → 找进程 → 判断泄漏 → 看 OOM/cgroup → 调配置或加内存。别被 buff/cache 吓到,也别用定时重启掩盖泄漏。

需要一台内存更充裕的机器做对照测试,可以按小时开一台萤光云香港 CN2 VPS,确认是容量还是代码问题。

相关推荐

赞(0)
未经允许不得转载:VPS知识分享站 » 云服务器内存占用高:OOM、swap 与泄漏排查清单