Linux内存耗尽(OOM Killer)故障排查与预防
概述
Linux 系统中,当物理内存和交换空间不足时,内核会触发 Out of Memory Killer(OOM Killer)机制,主动终止占用内存最多的进程以释放资源。这是一把”双刃剑”——它能防止系统完全卡死,但也可能导致关键业务进程被意外杀死,造成服务中断。本文从排查思路、应急处理、根因分析四个维度,介绍如何系统地应对 OOM 问题。
一、快速识别 OOM 发生
1.1 dmesg 查看内核日志
OOM 事件会记录在内核环形缓冲区,通过 dmesg 即可快速确认:
1 | # 查看 OOM 相关内核日志 |
日志中会显示被杀死进程的 PID、进程名、虚拟内存总量(total-vm)和实际物理内存占用(anon-rss)。
1.2 查看 OOM Score
每个进程的 /proc/<PID>/oom_score 文件记录了该进程被 OOM Killer 选中的优先级分数(0~1000),分数越高越容易被杀:
1 | # 查看所有进程的 OOM 分数 |
1.3 查看系统内存状态
1 | # 内存使用概览 |
二、应急处理流程
2.1 立即止血——恢复被杀死的重要进程
如果业务进程已被 OOM Kill,首先重启服务:
1 | # 查看系统日志确定被杀的进程和时间 |
2.2 临时释放内存
在定位根因期间,可通过以下方式临时缓解内存压力:
1 | # 清除页面缓存(需 root) |
2.3 防止关键进程被杀死
通过 oom_score_adj 可以保护重要进程,降低其被 OOM Killer 选中的概率:
1 | # 禁止 OOM Killer 杀死指定进程(设为 -1000) |
三、根因分析
3.1 分析内存消耗来源
1 | # 按实际物理内存排序查看进程 |
3.2 判断是内存泄漏还是正常高负载
内存泄漏特征: 进程内存只增不减,即使服务空闲也不释放。
正常高负载特征: 进程内存在某水位稳定,缓存随负载升降。
1 | # 多次采样观察内存趋势(每 30 秒一次) |
3.3 常见内存耗尽场景
| 场景 | 典型表现 | 排查命令 |
|---|---|---|
| Java/Node.js 堆内存未限制 | 进程虚拟内存持续增长 | jstat -gc <pid> / node --max-old-space-size |
| 临时文件未清理 | /tmp 或 /var/tmp 文件堆积 | du -sh /tmp/* |
| 共享内存未释放 | IPC 对象残留 | ipcs -m |
| 进程 fork 炸弹 | 大量子进程创建 | `ps aux |
| 缓存未及时清理 | Buff/Cache 占用过高 | free -h 中 available 列 |
四、预防措施
4.1 配置 swap 空间
1 | # 检查当前 swap |
4.2 设置 vm.overcommit_memory
1 | # vm.overcommit_memory = 0(默认,允许适度过量分配) |
4.3 限制容器/进程的内存
Docker 场景:
1 | # docker-compose.yml |
cgroup 限制:
1 | # 为进程组设置内存上限 |
4.4 部署 OOM 告警
提前感知内存压力,避免等 OOM 发生后才处理:
1 | # 监控脚本(内存使用 > 90% 时告警) |
总结
OOM 问题处理的关键在于”快识别、止血快、根因清、防复发”。大多数 OOM 悲剧并非系统资源真的不够,而是缺乏监控预警和合理的内存限制配置。建议在日常巡检中将内存使用率告警纳入必备项,并为关键服务配置 oom_score_adj 保护,同时通过 cgroup 或容器资源限制防止单一服务耗尽整机内存。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 体系所运维知识库!