Linux服务器OOM内存溢出,日志定位被杀死进程
服务器突然无法连接,或者SSH会话莫名断开,登录后free -h显示内存几乎耗尽?
这很可能是Linux的OOM Killer(内存溢出杀手)在作祟。
当物理内存和交换空间都严重不足时,内核会主动杀死一个或多个进程来释放内存,保证系统不至于完全崩溃。
本文面向零基础用户,教你如何从系统日志中精准找到哪个进程被杀死,并给出后续排查方向。
确认是否发生了OOM
在开始翻日志之前,先快速判断系统是否真的触发了OOM。
执行以下命令查看内核日志中的OOM关键词:
dmesg -T | grep -i -E 'oom|killed process'
如果输出中包含Out of memory: Killed process字样,说明OOM Killer已经行动。-T参数让时间戳更易读。
如果dmesg没有输出,继续用journalctl检查。
用journalctl定位被杀死进程
大多数现代Linux发行版(CentOS 7+、Ubuntu 16.04+)使用systemd,日志由journald管理。
运行:
journalctl -k --since "1 hour ago" | grep -i -E 'oom|killed process'
-k只显示内核消息,--since限定时间范围。
输出会明确告诉你:
- 被杀进程的PID
- 进程名(如
mysqld、php-fpm、java) - 该进程占用的物理内存页数和总虚拟内存
重点看Killed process那一行,它直接给出进程名和PID。
如果日志被轮转,可以查看/var/log/messages或/var/log/syslog:
grep -i -E 'oom|killed process' /var/log/messages
分析OOM触发前的内存状态
找到被杀的进程后,还需要了解当时的内存压力来源。
OOM日志通常会附带一段进程内存排名,类似:
[ pid ] uid tgid total_vm rss nr_ptes swapents oom_score_adj name
[ 1234] 0 1234 500000 400000 1000 0 0 mysqld
rss列表示进程实际使用的物理内存(页数),数值越大占用越高。
如果被杀的进程并非内存占用最高的,说明内核根据oom_score做了综合评分。
你可以通过/proc/查看当前评分,数值越高越容易被杀。
关键结论:被OOM杀死的进程不一定是内存占用最大的,但一定是内核认为“杀掉它释放内存最划算”的。
避免误判与后续处理
常见误区
- 只看
free命令的available列:free显示的是瞬时值,OOM发生瞬间的内存状态无法回看,必须依赖日志。 - 忽略cgroup限制:在容器或
systemd服务中,即使主机内存充足,cgroup内存上限被突破也会触发OOM,日志中会显示Memory cgroup out of memory。 - 日志被清理:如果
journalctl没有保留足够长时间的日志,可以编辑/etc/systemd/journald.conf,设置Storage=persistent和SystemMaxUse=500M,然后重启systemd-journald。
临时恢复与长期预防
临时恢复:重启被杀的进程服务,例如systemctl restart mysqld。
长期预防:
- 为关键进程设置
OOMScoreAdj,降低被杀优先级:echo -500 > /proc/(范围-1000到1000)。/oom_score_adj - 增加Swap空间,缓解突发内存峰值。
- 使用
systemd服务时,在unit文件中设置MemoryMax和MemoryHigh,避免单个服务拖垮整机。 - 部署监控,对
available内存和oom_kill计数设置告警。
验证OOM是否再次发生
处理完成后,观察一段时间,运行:
dmesg -T | grep -c 'Killed process'
计数不再增加,说明OOM未再触发。
同时用free -h和vmstat 1确认内存和swap使用平稳。
如果问题反复出现,需要结合业务日志分析内存泄漏,或考虑升级服务器内存。
本文覆盖的dmesg和journalctl命令适用于主流Linux发行版,具体输出格式可能因内核版本略有差异,以实际日志为准。