当前位置:首页 > 文章列表 > 文章 > linux > Linux cgroup v2用 memory.events 区分 oom 与 oom_kill的实现方法

Linux cgroup v2用 memory.events 区分 oom 与 oom_kill的实现方法

来源:17golang原创 2026-09-15 23:21:15 0浏览 收藏

排查容器或服务被 OOM 影响时,先不要把看到的 “oom” 直接等同于“进程已经被杀”。在 cgroup v2 中,memory.events 里的 oom 记录的是内存分配已经逼近失败的事件,而 oom_kill 记录的是 OOM killer 实际杀掉的进程数。两者要和 memory.maxmemory.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 是按键名组织的只读文件,不能假设字段永远按某个固定行号出现。

Linux cgroup v2 中 memory.max、memory.current 与 memory.events 的内存边界结构说明图
图1:cgroup v2 内存边界说明图,展示上限、当前用量与事件字段的静态关系。

按字段读取 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.maxoom 表示已经到达限制且分配即将失败;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

Linux cgroup v2 中 memory.events 与 memory.events.local 区分 oom 和 oom_kill 的结构说明图
图2:OOM 事件区分结构图,展示分配失败计数与进程终止计数不是同一个指标。

把判断结果落成排障清单

一次排障至少保留三个时间点:服务开始升高前、计数第一次增加后、恢复或重启后。每次记录 memory.maxmemory.currentmaxoomoom_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 是当前值,无法告诉你刚才是否碰过上限,也无法区分分配失败和进程终止。事件计数提供了“发生过什么”的历史线索,两者要配合读取。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Go crypto/tls按 ServerName 选择证书的实现方式Go crypto/tls按 ServerName 选择证书的实现方式
上一篇
Go crypto/tls按 ServerName 选择证书的实现方式
MCN第一次用LibTV怎么跑通一条内容?从选题卡、镜头表到审核回传
下一篇
MCN第一次用LibTV怎么跑通一条内容?从选题卡、镜头表到审核回传
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    43次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    140次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    75次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    42次使用
  • CMMLU中文大模型评估基准:功能、使用教程与应用场景解析
    CMMLU
    深入了解CMMLU中文评估基准,涵盖67个学科主题,提供数据集下载、Zero-shot/Five-shot评估方法及排行榜,助力优化中文语言模型性能。
    27次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码