小内存服务器排查内存占用与 OOM 的思路

2026-10-11 · 运维

一台 2G 内存的机器,free -h 显示还有几百兆可用,某个进程却被杀了。 这类情况我遇到过好几次,每次都是先在三个不同的「内存口径」之间绕一圈, 最后才想起来该看哪个。这里把顺序记一下。

第一步:分清 free 的三列

free -h
               total        used        free      shared  buff/cache   available
Mem:           1.9Gi       1.2Gi        86Mi        15Mi       790Mi       710Mi
Swap:          6.0Gi       1.2Gi       4.8Gi

判断内存是否紧张,看 available,不要看 free。 available 掉到总内存的 10% 以下,就该处理了。

第二步:确认 swap 是不是在硬撑

上面那台机器 available 还有 710Mi,看起来还行, 但 swap 已经用掉 1.2G。这意味着有大量页被换出到了磁盘, 进程虽然没被杀,实际响应速度会明显变慢。

看 swap 的换入换出速率,比看总量更有意义:

vmstat 1 5
# si/so 两列持续不为 0,说明正在频繁换页,性能已经在受影响

第三步:找真正的占用者

ps aux --sort=-%mem 按内存排序,但要注意 RSS 会把共享库重复计算, 多进程程序(比如浏览器内核、Node 的 worker)加起来的数字会虚高。 更准确的是按进程组看:

# 按 RSS 排序,取前 10
ps -eo pid,ppid,rss,comm --sort=-rss | head -11

# 同一个服务的所有进程合计(按进程名)
ps -eo rss,comm | awk '/nginx/{s+=$1} END{print s/1024" MB"}'

第四步:如果是被 cgroup 杀的,dmesg 会写明

这是最容易被忽略的一点。进程被 OOM killer 杀掉时, 如果是被某个 cgroup 的内存上限杀的,dmesg 里会带上 constraint=CONSTRAINT_MEMCG:

dmesg -T | grep -i -E 'oom|killed process' | tail -20

这时候去调大整机的 swap 是没用的——限制在 cgroup 那一层, 被杀的是那个 scope 里的进程,不是全系统缺内存。

第五步:看内存压力,而不是看余量

available 是个瞬时快照,压力是持续的过程。 PSI(Pressure Stall Information)能直接告诉你「有多少时间在等内存」:

cat /proc/pressure/memory
# some avg10=8.50 avg60=2.40 avg300=0.55
# full avg10=7.76 avg60=2.22 avg300=0.51

full 那一行表示「所有可运行任务都被内存卡住」的时间占比。 如果 full avg10 长期在两位数,说明机器已经在靠换页硬撑了, 这时候该做的是减负载,而不是继续往上堆服务。

实际处理顺序

  1. 看 available 和 PSI 的 full,判断是不是真的紧张
  2. 看 swap 的 si/so,判断是不是在频繁换页
  3. 按 RSS 找占用最大的进程组,确认有没有异常膨胀
  4. 如果进程是被杀的,去 dmesg 确认是全局 OOM 还是 cgroup OOM
  5. 最后才考虑加内存或加 swap,前面几步往往能直接定位到问题进程

小内存机器上,比起「加 swap 续命」,更有效的是给可能吃内存的操作设一个 cgroup 上限。 让它在自己的 scope 里被杀,而不是把整机拖进全局 OOM。

← 返回笔记列表