上一篇 下一篇 分享链接 返回 返回顶部

香港服务器进程突然被杀:如何结合OOM日志与进程内存占用排查

发布人:Minchunlin 发布时间:18小时前 阅读量:6
香港服务器进程突然被杀:如何结合OOM日志与进程内存占用排查

“进程被杀后,内存明明还很空闲”,并不能排除 OOM。进程退出会释放内存,事后看到的余量不代表故障前的状态;反过来,free 很小,也不等于内存已经耗尽。排查香港服务器上的进程突然消失,首先要区分:是内核因内存不足杀进程、服务所在的 cgroup 触及限额,还是人工操作、服务管理器等其他机制终止了进程。

优先顺序是:先锁定退出时间并查 OOM 证据,再判断整机内存与 cgroup 限制,接着关联进程占用,最后修复并在同类负载下验证。 仅凭 Killed、退出码 137 或重启后的内存截图,都不足以认定内存泄漏。

一、先确定“被杀”是否真的来自 OOM

以下命令面向 Linux。journalctlsystemctl 适用于使用 systemd 的系统,freepsvmstat 通常由 procps 工具集提供。查询原则上只读,但读取内核日志、其他用户的进程详情可能需要管理员权限。

排查前先记录故障时间、时区、服务名、是否自动重启。优先保存已有日志,不要急于重启或清理缓存,以免丢失现场。

将时间范围替换为实际故障前后窗口:

date -Is
sudo journalctl -k \
  --since "2026-01-01 10:00:00" \
  --until "2026-01-01 10:20:00" \
  --no-pager

日志较多时,可先筛选:

sudo journalctl -k --no-pager |
  grep -Ei 'out of memory|oom-kill|killed process|memory cgroup'

重点区分以下证据:

观察结果可以说明什么还需核对什么
内核日志出现 Out of memory: Killed process内核 OOM 机制选择并杀死了进程故障时间、PID、进程名,以及完整上下文
出现 Memory cgroup out of memory 或相关约束信息很可能涉及 cgroup 内存边界对应分组路径、限制和事件计数
服务显示 status=9/KILL,或运行环境报告 137进程收到 SIGKILL 的线索信号来自内核、管理员还是管理程序
只有应用报内存分配失败,没有被杀记录分配失败不等于 OOM Kill应用自身限制、地址空间及系统状态

筛选结果只用于定位,最终应阅读故障前后的完整日志。OOM 前文往往包含内存状态、任务列表和约束范围,单独截取 Killed process 一行容易误判。

如果服务器已经重启,可查询:

sudo journalctl --list-boots
sudo journalctl -k -b -1 --no-pager

只有上一轮启动日志被保留时,第二条命令才有结果。没有持久化日志、日志已轮转,或者当前处于无法查看宿主机内核日志的容器中,都可能查不到证据;“没查到”不等于“没有发生”。

二、理解整机内存:看 Available,不只看 free

Linux 会把部分空闲内存用于页缓存等用途,让重复读取更快。发生内存压力时,一部分缓存可以回收,因此不能将所有缓存都视为应用不可用的内存。

先检查当前状态:

free -h
grep -E 'MemTotal|MemFree|MemAvailable|Buffers|Cached|SwapTotal|SwapFree|SReclaimable|SUnreclaim|Dirty|Writeback' /proc/meminfo
vmstat 1 10

判断时注意三个边界:

  • MemAvailableMemFree 更适合评估整机余量。 它估计在不发生交换的情况下,还能向新应用提供多少内存,但不是某个容器或服务的可用额度。
  • 缓存并非都能立即回收。 脏页需要回写,不可回收的内核内存也不能像普通文件缓存一样释放。不能把全部 buff/cache 直接当作可用容量。
  • Swap 已用不等于正在严重换页。 冷数据可能仍留在交换区,应结合持续的换入换出、可用内存和业务延迟判断。

vmstat 第一行通常是自启动以来的统计,后续行才反映采样间隔。重点观察 siso 是否持续活跃;若同时出现 MemAvailable 偏低、业务响应变慢,说明内存压力可能已经影响运行。

内核 OOM 通常与分配请求无法在相应约束下得到满足有关,不是简单的“内存使用率达到某个固定百分比”。因此,故障后的这些命令只能说明现状,历史判断仍需监控和日志。

三、整机有余量时,继续检查 cgroup 限额

服务或容器可能被设置独立内存上限。即使香港服务器整体仍有可用内存,分组中的进程也可能因触及自身边界而被杀。

对 systemd 服务,将 your.service 替换为实际单元名:

systemctl show your.service \
  -p MainPID -p ControlGroup \
  -p MemoryCurrent -p MemoryHigh -p MemoryMax \
  -p Result -p ExecMainCode -p ExecMainStatus

sudo journalctl -u your.service \
  --since "2026-01-01 10:00:00" \
  --until "2026-01-01 10:20:00" \
  --no-pager

这些属性的支持情况取决于 systemd 版本及运行环境;空值不能直接解释为“没有限制”。服务重启后,状态字段也可能已反映新实例,应以故障窗口内的日志为准。

先确认 cgroup 挂载方式:

findmnt -t cgroup,cgroup2

若确认使用 cgroup v2,且挂载点为 /sys/fs/cgroup,可读取服务分组:

CG=$(systemctl show your.service -p ControlGroup --value)
if [ -n "$CG" ] && [ "$CG" != "/" ]; then
  sudo cat "/sys/fs/cgroup${CG}/memory.current"
  sudo cat "/sys/fs/cgroup${CG}/memory.max"
  sudo cat "/sys/fs/cgroup${CG}/memory.events"
fi

memory.current 是分组当前用量,不能等同于某一个进程的 RSS;memory.max 是该层级的硬限制,值为 max 表示这一层未设硬上限,但父级仍可能有限制。

memory.events 中:

  • max 增长:发生过触及硬限制边界的事件,不表示每次都杀了进程。
  • oom 增长:分组进入过 OOM 状态。
  • oom_kill 增长:属于该分组的进程被 OOM Killer 杀死过。

事件计数通常是累计值。应保存故障前后读数,结合内核日志和父级限制判断,不能仅凭一个非零数字确认本次故障。cgroup v1 的接口不同,不应直接套用上述文件名。

四、结合进程占用,区分“被杀对象”和“压力来源”

内核选择的被杀进程,不一定就是造成内存异常的进程。选择结果还受可选任务范围、内存占用及 oom_score_adj 等因素影响;触发分配失败的任务,也未必是最终受害者。

先找当前占用较高的进程:

ps -eo pid,ppid,user,comm,rss,vsz,%mem --sort=-rss | head -n 21

这里的 RSSVSZ 在该命令输出中以 KiB 表示:

  • RSS 反映当前驻留在物理内存中的部分。
  • VSZ 是虚拟地址空间大小,包含映射和预留空间,不能直接当作实际内存消耗。
  • 多进程 RSS 可能重复计算共享页,简单相加会高估占用。

对仍存活的目标进程进一步检查。下面的 PID 仅为示例,必须替换为实际值:

PID=1234
sudo grep -E 'VmRSS|VmHWM|VmSwap|RssAnon|RssFile|RssShmem' \
  "/proc/$PID/status"
sudo cat "/proc/$PID/smaps_rollup"
sudo cat "/proc/$PID/oom_score_adj"
cat "/proc/$PID/cgroup"

VmHWM 是该进程生命周期内的 RSS 高水位;Pss 按比例分摊共享页,更适合比较多进程实际承担的内存。部分内核没有 smaps_rollup,读取映射统计也有开销,不宜对大量进程进行高频扫描。

如果目标进程已经被杀,/proc/PID 就不存在了;重启后的进程即使名称相同,也不是原来的现场。这时应关联:

1. OOM 日志里的时间、PID、进程名及内存字段。

2. 同一时段的进程和 cgroup 用量监控。

3. 请求量、并发数、定时任务、发布与重启记录。

匿名内存随运行时间持续上升、负载回落后仍不回落,是继续排查泄漏或无界缓存的理由,但不是直接证明。分配器保留内存、运行时堆管理也可能让 RSS 保持高位,需要应用级分析确认。

五、根据证据修复,而不是先清缓存或扩大 Swap

修复应针对已经确认的分支:

已确认的问题优先处理需要防止的副作用
整机内存压力与高并发同步出现降低并发、拆分批量任务、错开高峰排队时间变长、吞吐下降
cgroup 上限小于合理工作集先减少工作集;整机有余量时再评估上调将局部 OOM 转移成整机 OOM
单进程内存持续增长检查无界缓存、对象持有、请求体及批处理规模单纯重启只会暂时掩盖问题
Swap 换入换出持续且延迟恶化优先压低活跃工作集继续扩大 Swap 可能加重抖动
没有内核 OOM 证据查服务超时、部署停止、人工操作和用户态内存管理日志不要把所有 SIGKILL 都归为内核 OOM

Swap 可以为可换出的匿名页提供缓冲,但不能修复泄漏,也不能保证避免 OOM;锁定页、不可回收内存及分组交换限制都会影响效果。

不要把主动清理缓存当作常规修复,也不要随意降低目标进程的 OOM 评分来“保住服务”:前者可能带来额外磁盘读取,后者可能让其他关键进程成为受害者。

调整内存限制、并发数或应用配置前,应备份原配置、记录旧值,并确认是否需要重启。一次只改一类变量,在可控窗口实施;如果出现延迟恶化、整机余量下降或其他服务异常,应恢复原配置并按原方式重新加载或重启。

六、修复后,用同类负载验证是否真正稳定

“服务能启动”只是恢复可用,不代表问题解决。验证应覆盖曾经触发故障的负载条件,例如同类批量任务、请求高峰或足够长的运行周期。

至少同时确认:

  • 故障窗口之后没有新增相关 OOM 日志,服务也未发生异常重启。
  • cgroup 的 oomoom_kill 等事件计数没有继续增加;分组重建导致计数重置时,重新建立基线。
  • MemAvailable 在负载回落后恢复,而非持续走低。
  • 目标进程 RSS/PSS 与业务负载存在合理关系,峰值没有逐轮抬升。
  • Swap 活动、响应时间和错误率没有因修复而恶化。

如果只有进程退出后的内存截图,没有历史日志或采样,最多只能判断当前状态,无法可靠还原故障前的压力来源。此时应补齐整机、cgroup 和进程三层监控。只有把退出事件、内存边界、占用变化和业务负载对齐到同一时间窗口,才能判断这次进程被杀是容量不足、限额不当,还是应用内存行为异常。

目录结构
全文