云服务器进程被莫名杀掉?从 free、dmesg 到 OOM Killer 的排查顺序
服务跑着跑着突然没了,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
注意这只是“换一个进程被杀”,不解决内存不够的根因,不要对所有服务都调低。
六、止血与长期措施
止血:
- 重启泄漏的服务,先恢复业务;
- 临时加 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 定位进程 → 记录趋势区分泄漏与峰值 → 设上限和告警。按这个顺序走,大多数“进程莫名消失”的问题都能在半小时内定位。
- 点赞
- 收藏
- 关注作者
评论(0)