理解 Swap 与 OOM:Linux 内存不足时发生什么
在 Linux 系统中,物理内存不仅用于运行进程,还会被大量分配给 Page Cache 以加速磁盘 I/O。当可用内存低于内核水位线时,系统会优先回收 Page Cache;若内存压力持续升高,内核会将不活跃的匿名页写入磁盘上的 Swap 分区或交换文件,从而腾出物理内存。需要明确的是,Swap 并不等同于“虚拟内存”,虚拟内存是进程寻址的抽象空间,而 Swap 仅是物理内存不足时的后备存储介质。当 Swap 耗尽或系统禁用 Swap 且内存彻底枯竭时,内核的 OOM Killer 将被触发。OOM Killer 会遍历所有用户态进程,根据进程的内存占用量、运行时间、优先级以及是否拥有特权等维度计算综合得分,最终选择得分最高、对系统影响相对最小的进程强制终止,以保障内核存活。
查看与调整 Swap:从现状检查到 swappiness
检查 Swap 状态最直观的命令是 free -h,它会清晰展示 Swap 的总量、已用与空闲情况;结合 cat /proc/meminfo | grep -i swap 可获取更底层的统计信息。若需新增 Swap,可使用 dd 或 fallocate 创建文件,通过 mkswap 格式化,并用 swapon /path/to/swapfile 启用,最后执行 swapon --show 验证。控制 Swap 使用频率的核心参数是 vm.swappiness(取值 0-100)。临时调整执行 sysctl vm.swappiness=60,持久化则需在 /etc/sysctl.conf 中添加对应配置并执行 sysctl -p。许多运维人员误以为“Swap 越少越好”甚至直接设为 0,这会导致内核在内存紧张时过早触发 OOM Killer,反而失去 Swap 提供的缓冲与容错能力。合理设置 swappiness 能让内核在内存压力下更平滑地过渡,避免服务瞬间雪崩。

调整 oom_score_adj:控制 OOM 时谁更容易被杀
oom_score 是内核根据当前内存状态动态计算的原始得分,而 oom_score_adj 是用户可手动干预的偏移量(范围 -1000 至 1000)。查看某进程评分可执行 cat /proc/ 与 cat /proc/。通过 echo -500 > /proc/ 可降低该进程的 OOM 优先级,使其更难被选中;反之,设为正值会提高其被杀概率。该操作需 root 权限,且调整仅对当前运行实例生效,进程重启或系统重启后配置将自动重置。在实际生产中,常将数据库或核心网关的 oom_score_adj 设为负值以保护关键业务,但需注意:若系统内存彻底耗尽,即使设为 -1000 的进程仍可能被内核强制回收,因此该参数仅用于相对优先级排序,不能作为绝对免死金牌。

验证调整是否生效:监控内存压力与 OOM 事件
调整参数后必须建立可观测的验证闭环。使用 vmstat 2 可实时观察 si 与 so 列,若数值持续为 0 或极低,说明 Swap 压力已缓解。现代内核支持 PSI,通过 cat /proc/pressure/memory 可查看内存阻塞的绝对时间与百分比,比传统指标更精准。若怀疑发生 OOM,应使用 dmesg -T | grep -i oom 或 journalctl -k --grep="Out of memory" 检索内核日志。日志中会明确打印触发 OOM 的时间、被杀进程的 PID、名称及其当时的 oom_score。结合 free -m 的历史快照与监控面板趋势,可交叉验证 swappiness 或 oom_score_adj 调整是否真正改变了内存回收行为,避免盲调导致问题掩盖。

常见误区与安全实践:不要把 Swap 和 oom_score_adj 当万能开关
生产环境中极易陷入配置误区:例如盲目将 swappiness 设为 100 会导致频繁磁盘 I/O 拖垮系统,设为 0 则剥夺了内核的弹性缓冲;随意给大量进程赋予负 oom_score_adj 会使 OOM Killer 失去选择空间,最终可能误杀系统守护进程甚至引发内核 Panic。在容器化场景下,仅调整宿主机参数而忽略 Docker 或 Kubernetes 的 cgroup 内存限制,会导致调整完全失效。安全实践应遵循“先观测、再调整、最后验证”原则:部署 Prometheus 持续采集内存水位与 Swap 使用率;在变更窗口期逐步微调参数;通过压力测试模拟内存泄漏场景,确认关键进程存活且非核心进程按预期退出。内存管理没有银弹,唯有结合业务特征与可观测数据,才能实现稳定与性能的平衡。

