Linux cgroup v2用 memory.events 区分 oom 与 oom_kill的实现方法
来源:17golang原创
时间:2026-09-15 23:21:15 281浏览 收藏
排查容器或服务被 OOM 影响时,先不要把看到的 “oom” 直接等同于“进程已经被杀”。在 cgroup v2 中,memory.events 里的 oom 记录的是内存分配已经逼近失败的事件,而 oom_kill 记录的是 OOM killer 实际杀掉的进程数。两者要和 memory.max、memory.current 一起看,结论才不会偏。
oom增加,表示一次分配走到了 OOM 处理边界,不保证已经发生进程终止。oom_kill增加,才说明有进程被某种 OOM killer 杀掉。memory.events默认包含子 cgroup 的层级统计;只看当前组要读memory.events.local。
先把 cgroup 的内存边界读清楚
我更习惯先把观察对象固定成一个 cgroup 目录,再读四个文件。下面的路径只是示例,实际环境要替换成服务所在的 cgroup:
# 只读取目标 cgroup 的内存边界和事件文件,不扫描宿主机所有进程
CG=/sys/fs/cgroup/demo-worker
# memory.max 是硬上限,memory.current 是当前统计用量
printf 'max: '; cat "$CG/memory.max"
printf 'current: '; cat "$CG/memory.current"
printf '\n[events]\n'; cat "$CG/memory.events"
printf '\n[local events]\n'; cat "$CG/memory.events.local" 2>/dev/null || true
memory.max 返回字节数,也可能是 max,表示该组没有设置数值上限;memory.current 用来判断当前用量是否贴近上限。memory.events 是按键名组织的只读文件,不能假设字段永远按某个固定行号出现。

按字段读取 oom、oom_kill 和 max
生产脚本不要用 sed -n '4p' 这种按行号取值方式。用键名读取,既能容忍内核新增字段,也能把一次快照保存下来与下一次比较:
# 从 key value 文件中按字段名取计数;字段缺失时返回 0,便于兼容旧环境
event_value() {
local key="$1"
awk -v wanted="$key" '$1 == wanted { print $2; found=1; exit } END { if (!found) print 0 }' "$CG/memory.events"
}
# 这些是单调计数器,重点看本次采样相对上次的增量
OOM=$(event_value oom)
OOM_KILL=$(event_value oom_kill)
MAX_HIT=$(event_value max)
printf 'oom=%s oom_kill=%s max=%s\n' "$OOM" "$OOM_KILL" "$MAX_HIT"
内核文档对三个字段的含义不同:max 表示用量曾经要超过 memory.max;oom 表示已经到达限制且分配即将失败;oom_kill 表示属于该 cgroup 的进程被 OOM killer 终止。也就是说,oom 增加而 oom_kill 不变,并不矛盾,可能是分配以 -ENOMEM 返回、重试后成功,或者调用路径不适合触发 OOM killer。
oom 和 oom_kill 要按两个事实判断
可以把判断拆成“资源边界事实”和“进程结果事实”。第一组只说明内存分配遇到了压力,第二组才说明业务进程真的少了。不要用一条计数替代另一条:
| 观察结果 | 应作的判断 | 下一步 |
|---|---|---|
max 增加,oom 不变 | 触碰过硬上限,但尚未确认 OOM 分配失败 | 对照 memory.current 与业务峰值 |
oom 增加,oom_kill 不变 | 出现过 OOM 边界,可能由分配失败或重试结束 | 看服务错误处理和申请内存的调用方 |
oom_kill 增加 | 确实发生了进程终止 | 记录被杀进程、重启次数和内存上限变更 |
还有一个容易误读的点:memory.events 默认是层级统计,父 cgroup 的值可能包含子 cgroup 的事件。如果服务组里又划分了 worker 子组,父组的 oom 增加不一定发生在父组自己的进程上。要看当前组本地事件,就读取 memory.events.local。

把判断结果落成排障清单
一次排障至少保留三个时间点:服务开始升高前、计数第一次增加后、恢复或重启后。每次记录 memory.max、memory.current、max、oom、oom_kill 五个值,并注明读取的是层级文件还是 local 文件。
- 只有
memory.current长期接近上限:先检查缓存、批量任务和并发峰值,不要立刻归因于 OOM killer。 oom持续增加:检查申请失败后的错误处理,确认业务是否把-ENOMEM当成普通空结果。oom_kill增加:把进程退出时间与服务重启记录对齐,再决定是降低峰值、提高上限,还是拆分子 cgroup。
字段定义可继续查阅:https://docs.kernel.org/admin-guide/cgroup-v2.html。这个方法的边界也很明确:它解释 cgroup 内存事件计数,不代替宿主机全局内存、swap、内核日志和应用自身指标的联合排查。
相关问题
memory.events 和 memory.events.local 应该读哪个?
要看整个 cgroup 子树的累计影响,读 memory.events;只想判断当前组自己发生了什么,读 memory.events.local。监控父组时最好同时记录二者,避免把子组事件算到错误服务上。
oom 增加但 oom_kill 为零是不是误报?
不是误报。它表示分配曾经到达 OOM 边界,但结果可能是返回分配失败、被调用方忽略,或经过回收与重试后继续运行;只有 oom_kill 增加才确认有进程被杀。
为什么不能只看 memory.current?
memory.current 是当前值,无法告诉你刚才是否碰过上限,也无法区分分配失败和进程终止。事件计数提供了“发生过什么”的历史线索,两者要配合读取。
-
426 收藏
-
387 收藏
-
242 收藏
-
238 收藏
-
402 收藏
-
114 收藏
-
文章 · linux | 3小时前 | Linux · systemd · 日志排查 · journalctl · 运维命令 · Linux journalctl journalctl按unit筛选日志 journalctl时间范围 systemd服务日志排查 journalctl日志为空372 收藏
-
153 收藏
-
文章 · linux | 6小时前 | linux运维 · systemd服务 · 故障重启 · 服务限流 · Linux systemd StartLimitBurst StartLimitIntervalSec Restart211 收藏
-
209 收藏
-
206 收藏
-
381 收藏
-
文章 · linux | 10小时前 | cron · 定时任务 · Linux · shell · crontab · Linux cron相对路径失败 cron找不到文件 crontab工作目录 cron环境变量 Linux定时任务排查360 收藏
-
文章 · linux | 11小时前 | https · TLS · linux运维 · OpenSSL · 证书排障 · Linux OpenSSL tls 证书链 SNI s_client SAN216 收藏
-
436 收藏
-
文章 · linux | 14小时前 | 命名空间 · 容器隔离 · 挂载 · Linux教程 · Linux mount namespace bind mount mount propagation314 收藏
-
149 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习