云服务器进程被莫名杀掉?从 free、dmesg 到 OOM Killer 的排查顺序

举报
yd_275727902 发表于 2026/11/10 18:56:27 2026/11/10
【摘要】 服务跑着跑着突然没了,systemd 显示 killed,或者 Java/Python 进程无声退出、日志最后一行戛然而止——这类问题很多时候是内存耗尽触发了内核的 OOM Killer。别急着加内存,先按下面顺序把“是不是 OOM、谁吃的内存、为什么吃这么多”说清楚。命令在 EulerOS、CentOS 7+/8、Ubuntu 20.04+ 上通用。 一、先确认是不是 OOM 杀的dmes...

服务跑着跑着突然没了,systemd 显示 killed,或者 Java/Python 进程无声退出、日志最后一行戛然而止——这类问题很多时候是内存耗尽触发了内核的 OOM Killer。别急着加内存,先按下面顺序把“是不是 OOM、谁吃的内存、为什么吃这么多”说清楚。命令在 EulerOS、CentOS 7+/8、Ubuntu 20.04+ 上通用。

一、先确认是不是 OOM 杀的

dmesg -T | grep -iE 'out of memory|oom-killer|killed process'
journalctl -k --since "2 hours ago" | grep -i oom

看到类似 Out of memory: Killed process 12345 (java) total-vm:... anon-rss:... 就基本坐实了。重点记下三样:被杀进程名、anon-rss(它实际占用的物理内存)、发生时间。

如果是容器(Docker/K8s)里的进程,还要看 cgroup 级别的 OOM:

docker inspect <容器> --format '{{.State.OOMKilled}}'
kubectl describe pod <pod> | grep -i -A3 'last state'   # Reason: OOMKilled

cgroup 内存上限触发的 OOM 和整机内存耗尽是两回事,前者调容器 limit,后者看整机。

二、看整机内存的真实情况

free -h

不要只盯 free 列。Linux 会把空闲内存拿去做页缓存,真正该看的是 available。available 长期接近 0、且 swap 在持续增长,才说明内存真的紧张。

再看一下内存的大头去了哪里:

grep -E 'MemTotal|MemAvailable|Cached|Shmem|Slab|SReclaimable|SUnreclaim|HugePages_Total' /proc/meminfo
  • Shmem 很大:检查 /dev/shm、tmpfs 挂载点(df -h -t tmpfs)是否被写满。
  • SUnreclaim 很大:可能是内核对象泄漏,用 slabtop -o | head -20 看哪类 slab 最多(常见是 dentry、连接跟踪表)。
  • HugePages_Total 不为 0:大页是预留的,不会被普通进程使用,预留过多会挤占可用内存。

三、找出吃内存的进程

ps aux --sort=-rss | head -15

RSS 是常驻物理内存,VSZ 是虚拟内存,虚拟内存大不代表有问题。想看更准确的占用(扣除共享页),可以用:

# 按 PSS 排序,需安装 smem
smem -rs pss | head -15
# 或查看单个进程
grep -E 'Rss|Pss|Swap' /proc/<PID>/smaps_rollup

如果是 Java 进程,RSS 远大于 -Xmx 很常见:堆外内存、元空间、线程栈、直接内存都会算进去。可以开启 -XX:NativeMemoryTracking=summary 后用 jcmd <PID> VM.native_memory summary 分解。

四、判断是泄漏还是峰值

只看一次快照很容易误判。用一个简单的循环记录趋势:

while true; do
  echo "$(date '+%F %T') $(ps -o rss= -p <PID>)" >> /tmp/rss.log
  sleep 60
done
  • 曲线持续单调上涨、不回落:大概率是泄漏,需要应用侧排查(缓存无上限、连接未释放、全局集合只增不删)。
  • 平时平稳、某个时间点突刺:通常是批处理、大查询、一次性加载大文件,需要限流或分批。

sar -r 1 10(sysstat 包)也能查看历史内存使用,配合 OOM 发生时间点对照很有用。

五、理解 OOM Killer 为什么选中它

内核按 oom_score 选择牺牲者,分数越高越先被杀:

for p in /proc/[0-9]*; do
  printf "%s %s %s\n" "$(cat $p/oom_score 2>/dev/null)" "${p#/proc/}" "$(cat $p/comm 2>/dev/null)"
done | sort -rn | head -10

对关键进程(比如 sshd、数据库主进程)可以降低被杀的优先级:

# systemd 服务里设置
[Service]
OOMScoreAdjust=-500

注意这只是“换一个进程被杀”,不解决内存不够的根因,不要对所有服务都调低。

六、止血与长期措施

止血:

  1. 重启泄漏的服务,先恢复业务;
  2. 临时加 swap 争取时间(生产环境数据库不建议依赖 swap):
fallocate -l 2G /swapfile && chmod 600 /swapfile
mkswap /swapfile && swapon /swapfile

长期:

  • 给服务设内存上限,让它在自己的边界内失败,而不是拖垮整机:systemd 用 MemoryMax=,容器用 --memory / resources.limits.memory。
  • JVM 设置合理的 -Xmx,一般留出 25%~30% 给堆外与系统。
  • 在云监控里为“内存使用率”和“可用内存”配置告警,阈值建议 85%,比等 OOM 发生更早发现问题。
  • 内存长期高位且业务确实增长,再考虑升级规格。

小结

排查顺序:dmesg 确认 OOM → free 看 available → /proc/meminfo 找大头 → ps/smem 定位进程 → 记录趋势区分泄漏与峰值 → 设上限和告警。按这个顺序走,大多数“进程莫名消失”的问题都能在半小时内定位。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。