Linux 里“物理内存没满但 swap 快没了”是很常见的现象,不一定代表马上 OOM,但确实值得查。核心原因一句话:内核不是“内存满了才用 swap”,而是按自己的回收策略把“觉得以后用不到的匿名页”换出去。下面把常见原因和排查顺序说清楚。

一、为什么内存没满 swap 也在涨

1)swappiness 设置偏高(最常见)

  • swappiness=60(很多发行版默认)意思是:
    哪怕还有不少 page cache 可清,也愿意把匿名内存换到 swap
  • 结果:空闲内存还不少,swap 已经在用了

查看:

1
cat /proc/sys/vm/swappiness

临时调低(比如 10~20):

1
sysctl vm.swappiness=10

永久改:/etc/sysctl.d/99-swap.conf

1
vm.swappiness=10

注意:

  • swappiness=0 不是“禁用 swap”,在 3.5+ 内核里只是“绝不为了清 page cache 换匿名页”,page cache 真没了还是会换;生产别设 0,数据库/Java 通常 10 左右
  • 数据库/Java 服务通常建议 10 左右

2)长期运行后“冷匿名页”被换出

  • 某些进程(含 java/node/agent)起来分配一大块内存
  • 其中一部分很久没访问(冷页)
  • 内核在“内存压力不大”时也会做后台回收,把它换到 swap
  • 表现:内存占用 50%,swap 用了几 GB

这是正常机制,只要不再频繁访问这些页,就不会有性能问题。

3)某个进程在持续吃匿名内存

  • 内存“看起来没满”是因为:

    • cache/buffer 占了一部分
    • 可用内存(available)比 free
  • 但匿名内存(heap/mmap 匿名)一直在涨
  • 内核先把冷的换出去,swap 就涨了

看真实压力用:

1
2
free -h
cat /proc/meminfo | grep -E 'MemAvailable|SwapTotal|SwapFree'

4)容器 / JVM / 大页场景

  • JVM-Xmx 分配堆,即使不用也会留匿名页,可能被换出
  • K8s 容器:limit 没设准,节点层看内存没满,但 cgroup 内被打爆(节点 cat /sys/fs/cgroup/<c>/memory.swap.current 才是容器内真相)
  • Transparent Huge Pages:THP 下匿名页更大,换出更“显眼”
  • 顺带一句:开了 zswap/zram 的话,swap 涨可能是压缩内存,不是磁盘 IO,不一定是坏事

5)swap 只进不出(用完不回收)

  • 如果之后内存真紧了,内核会把 swap 里的页换回来
  • 但如果你看到:

    • swap 使用量只涨不跌
    • 同时有少量 si/so
    • 说明有进程在周期性访问那些冷页(thrashing 前兆)

二、快速自查顺序(建议你照着跑)

1. 哪些进程占用了 swap

1
2
3
find /proc -maxdepth 2 -name status \
-exec awk '/^Pid:/{p=$2} /^VmSwap:/{if($2>0) print p, $2" kB"}' {} \; \
2>/dev/null | sort -k2 -n -r | head

或直接:

1
smem -s swap -r | head

2. 是不是在换入换出(性能问题关键)

1
vmstat 1

si so

  • 都是 0 → swap 占了但没影响性能
  • 持续 >0 → 有抖动风险

要是内核够新(4.20+),顺手瞄一眼 PSI,比 vmstat 灵:

1
cat /proc/pressure/memory

some avg10 持续大于 0 就说明已经在因内存回收卡了,不用等 si/so 起来。

3. 内存口径别看错

1
free -h

重点看:

  • available 还够不够
  • buff/cache 是不是很大(可被回收)

4. swappiness 是多少

1
cat /proc/sys/vm/swappiness

三、该不该慌 / 怎么办

情况 A:swap 占了,但 si/so=0,内存 available 充足

不用管,属于内核正常行为
可选:调低 swappiness 让 swap 不好看

情况 B:swap 涨 + 偶尔 si/so + 延迟变高

→ 调 swappiness=10,检查是否有 Java/agent 常驻大内存

情况 C:swap 快满 + si/so 持续 >0

→ 真有内存压力:

  • 找 swap 占用最高的进程
  • 扩内存 / 缩服务 / 限 cgroup
  • 实在要清 swap,别轻易 swapoff -a(内存不够会卡死、OOM 乱杀),优先重启高占用进程;真要 swapoff 也得确认 MemAvailable 明显大于 SwapUsed 且在维护窗口内

四、一个反直觉结论

Linux 不是“内存满了才用 swap”,它会在“我觉得这页以后用不到”时就用 swap,所以“内存没满 swap 快满”完全合法。

AI