如果你的服务器突然像死机一样卡顿,SSH半天敲不出一个字符,登录上去发现大规模服务进程集体消失,或者干脆远程连接直接掉线。不要急着怀疑被入侵,先看一个最容易被新手忽略的记录:dmesg里那一屏Out of memory: Kill process。这种情况基本就是Linux遇到了OOM(Out Of Memory,内存耗尽)。
OOM不是硬件故障,也不是玄学,它是Linux内核的一道“自毁式”保护机制:当物理内存和Swap被消耗到极限,系统为了活下去,会强制挑选进程并杀掉,把内存还给系统。问题是,它挑的进程往往是你的核心服务——数据库、缓存、Java应用。这个指南不打算从枯燥的内核源码讲起,我直接把过去几年在Linux服务器上排查OOM的完整思路、命令、拆解逻辑和警务经验整理出来,从“为什么会杀进程”到“怎么快速定位凶手是谁”,再到“如何彻底优化避免再犯”,一次性讲透。不管你是刚上手的运维,还是被线上OOM折磨过的后端开发,这篇都能帮你少走弯路。
1. 先搞清楚 OOM 到底是怎么触发的
1.1 内核的“内存账本”远比想象复杂
很多新手的第一反应是“我的内存是不是买小了”。实际上,OOM的触发点从来不是某一个单纯的内存条容量,而是内核自己那套完整的内存分账体系。现代Linux内核会把物理内存按用途拆分成很多部分:进程的私有数据(anon_rss)、文件页缓存(page cache)、内核自身的slab对象、页表项,甚至临时映射都需要占用物理内存。你平时用free -h看到的那一行used,指的只是“被某个具体对象占住”的内存,真正危险的是当你申请新内存的时刻,内核突然发现“账上已经没有可用页了,连Swap也装不下”,这个时候OOM就会被激活。
我见过一个非常典型的场景:一台32GB内存的服务器,从free看还剩下6GB可用,以为很安全,结果线上服务照样触发OOM。后来一查原因是该服务器上的应用程序疯狂写日志,因为物理内存里的page cache会被写回机制占用大量缓冲,同时一个Java服务申请了一个非常大的堆内存,瞬间内外交困。所以,你在诊断OOM的时候,不能只盯着free的输出,必须有全局观:进程内存、页缓存、内核态内存、磁盘I/O之间的交互失衡,才是触发OOM的导火索。
1.2 OOM 不只是“物理内存不够”这么简单
这里必须纠正一个常见误区:OOM和“物理内存彻底用完”其实不是一回事。Linux内核有一个投机取巧的设计:进程申请内存时,只要虚拟地址空间允许,内核通常都会放行(默认策略),并不立即分配真正的物理页。这种机制叫做内存过量使用(Overcommit)。它带来一个后果——运行中的服务总申请量加在一起,可能远远超过物理内存+Swap的总和。当所有进程开始真实地写入内存页时,物理内存才会被真正耗尽,这时候内核的“暴脾气”OOM Killer才会登场。
还有一个容易被忽视的触发场景:Cgroup内存限制。现在的容器环境,比如Docker、Kubernetes,每个容器都有独立的Cgroup内存上限。假设宿主机内存剩余100GB,但某个容器的内存Cgroup限额只有2GB,这个容器内一旦内存跑满,内核就会对这个容器执行OOM Kill,而宿主机完全无感。所以线上问题排查时,我习惯先确认环境中有没有容器隔离,否则你在宿主机上查半天内存,也找不到真正被限制的那个进程。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 快速定位:日志才是第一现场
2.1 dmesg 里的 OOM 日志怎么看
当内核执行OOM的时候,它会往内核环形缓冲区里写入一条非常完整的元凶信息。第一步永远都是翻日志。不同发行版的中转位置略有差异,但内核日志总体可以通过下面几个命令来查:
bash复制# 直接看内核环形缓冲区,最经典的方式
dmesg | grep -i -B5 -A15 "out of memory"
# 如果你的日志比较大,可以额外看文件
journalctl -k | grep -
