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 | free -h |
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 | find /proc -maxdepth 2 -name status \ |
或直接:
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
评论已关闭