讲解 Linux OOM Killer 内核证据、主机与 cgroup OOM 区分、Docker OOMKilled、内存趋势、Swap 和 systemd 限制。
Linux 进程突然退出并出现 Killed,不一定是应用主动崩溃。可能是整台服务器内存耗尽触发内核 OOM Killer,也可能是容器或 systemd 服务达到 cgroup 内存上限。排查时必须先找终止证据,再判断是主机级内存压力、服务限制还是人工信号。

先在内核和服务日志中找证据
journalctl -k --since '-2 hours' | grep -Ei 'out of memory|oom-kill|killed process'
dmesg -T | grep -Ei 'out of memory|oom-kill|killed process'
systemctl status APP.service --no-pager
journalctl -u APP.service --since '-2 hours' --no-pager
内核日志通常会记录触发范围、被杀进程、PID 和内存信息。systemd 服务如果因信号退出,也可能显示 Result=oom-kill 或退出信号。没有 OOM 记录时,还要检查应用日志、人工 kill、健康检查重启和部署系统。
区分主机 OOM 和 cgroup OOM
free -h
swapon --show
cat /proc/meminfo | head -20
systemctl show APP.service -p MemoryCurrent -p MemoryPeak -p MemoryHigh -p MemoryMax -p OOMPolicy
主机 OOM 发生在系统整体难以满足内存分配时;cgroup OOM 则可能在服务器仍有空闲内存时发生,因为该服务或容器达到 memory.max、MemoryMax= 等硬限制。不能只看故障后的 free -h,因为进程被杀后内存已经释放。
Docker 容器怎么确认
docker inspect CONTAINER --format '{{.State.OOMKilled}} {{.State.ExitCode}}'
docker stats --no-stream
docker inspect CONTAINER --format '{{.HostConfig.Memory}} {{.HostConfig.MemorySwap}}'
OOMKilled=true 是重要证据,但还要结合容器重启策略和宿主机日志。退出码 137 表示进程收到 SIGKILL,可能来自 OOM,也可能由人工或编排系统发送,不能只凭退出码下结论。
找出谁在持续占用内存
ps -eo pid,ppid,user,%mem,rss,vsz,comm --sort=-rss | head -20
systemd-cgtop --depth=3
vmstat 1 10
cat /proc/pressure/memory
RSS 反映进程驻留物理内存,但共享页、页缓存、匿名内存和 cgroup 统计口径不同。要结合应用指标观察趋势:是否随请求量上升、任务结束后是否回落、是否在固定批处理时峰值增长,以及部署后基线是否改变。
Swap 能不能解决 OOM
适量 Swap 可以为短时峰值提供缓冲,但会增加延迟,也不能修复持续内存泄漏。数据库和低延迟服务需要评估换页影响。若没有 Swap,可先参考站内的 Ubuntu Swap 配置教程,但扩容前仍应找出内存增长来源。
处理策略按原因选择
| 原因 | 处理方向 | 验证 |
|---|---|---|
| 持续内存泄漏 | 修复应用、限制并发、设置可控重启 | 观察相同负载下内存曲线 |
| 批处理峰值 | 拆批、限并发、错峰或增加资源 | 峰值低于安全水位且任务完整 |
| cgroup 上限过低 | 核对工作集后调整 MemoryMax 或容器限制 | 限制仍能约束异常增长 |
| 整机容量不足 | 减少同机服务、增加内存或重新规划实例 | 压力期间无持续回收与 OOM |
systemd 限制怎么调整
不要直接取消所有限制。可以先设置告警或软压力阈值,再保留合理硬上限,防止单个服务拖垮整台主机。
[Service]
MemoryHigh=1536M
MemoryMax=2G
OOMPolicy=stop
sudo systemctl daemon-reload
sudo systemctl restart APP.service
systemctl show APP.service -p MemoryCurrent -p MemoryPeak -p MemoryHigh -p MemoryMax
示例数值不能直接用于生产,应根据实际工作集、峰值和主机容量计算。重启会中断服务,先确认高可用或维护窗口。
建立提前预警
- 监控主机 MemAvailable、Swap 使用和内存压力;
- 监控服务或容器工作集与内存上限比例;
- 保存内核日志,避免重启后证据丢失;
- 对批处理队列、请求并发和应用堆设置业务指标;
- 在达到硬限制前告警,而不是等进程被杀。
操作边界
不建议关闭 OOM Killer 来“保住进程”,这可能让任务长期阻塞并拖垮整台服务器。提高内存上限、增加 Swap 或升级规格都只是容量措施;若应用持续无界增长,最终仍会再次耗尽资源。

