登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  linux

Linux cgroup v2 memory.events 中 high 与 oom 如何区分

来源:17golang原创

时间:2026-10-24 22:27:59 333浏览 收藏

Linux cgroup v2 中,memory.events 的 high 和 oom 不是同一个级别的告警:high 表示工作负载越过 memory.high 后被节流并进行直接回收,oom 表示已经触到内存限制,新的分配可能失败。前者重点看性能抖动,后者重点看分配失败和进程被杀。

官方文档:https://docs.kernel.org/admin-guide/cgroup-v2.html

快速判断:只有 high 增长,先查软上限和回收延迟;oom 或 oom_kill 增长,则要按硬上限、分配失败和进程退出路径排查。不要把 high 计数直接当成 OOM。

先看字段:high、max、oom 和 oom_kill 各自说明什么

memory.events 是按键值记录的事件计数器,常见字段可以按严重程度和处置动作分开理解:

字段含义优先关注
high超过 memory.high,任务被节流并执行直接回收延迟、吞吐和软上限是否过低
max使用量接近或越过 memory.max,内核尝试把它压回边界硬限制、回收是否能释放空间
oom达到限制且分配即将失败,进入 OOM 状态的次数失败分配和 OOM 处置路径
oom_kill该 cgroup 中被 OOM killer 杀掉的进程次数退出进程、重启与工作负载影响

因此,high 更像“内存预算已经影响性能”的信号,oom 更像“继续分配已经有失败风险”的信号。它们可以先后出现,也可能只出现其中一种;不能只看一个字段就推断完整根因。

memory.high、memory.max、memory.events 中 high 与 oom 的静态边界关系图
图1:内存事件边界说明图,展示 memory.high 的节流回收与 memory.max 的 OOM 风险关系;这是原创结构图,不是运行截图或实测证据。

看限制:为什么 high 通常先影响性能,oom 才逼近失败

memory.high 是内存控制器的软边界。超过它后,cgroup 内的任务会被限制运行并被引导执行直接回收,目标是给管理程序留下调节内存或终止工作负载的机会。这个阶段可能出现请求变慢、GC 或缓存回收频繁,但不等于已经发生 OOM killer。

memory.max 是硬边界。内核会先尝试回收;如果无法把使用量降回限制以内,分配就可能进入 OOM 状态。oom 增长说明已经走到这个边界附近,oom_kill 是否增长则取决于最终是否真的有进程被 OOM killer 处置。

可以把两者看成两种不同的选型:想提前控制延迟,调优 memory.high;想限制工作负载最大占用,使用 memory.max,同时为 OOM 和恢复预留处理方案。提高 memory.high 不会改变 memory.max,设置 memory.max 也不会消除已经发生的 high 计数。

看归属:先区分层级统计,再判断当前用量

排查时不要只复制一行计数器。memory.events 的字段是层级统计,可能包含后代 cgroup 的事件;如果只想看当前 cgroup 自己产生的事件,应读取 memory.events.local。事件文件记录的是累计次数,不是当前内存用量,实时用量要结合 memory.current。

# 把目标 cgroup 改成实际的服务目录
CG=/sys/fs/cgroup/my-service

# 读取层级事件:可能包含后代 cgroup 的贡献
cat "$CG/memory.events"

# 只看当前层级事件,适合判断本组是否直接触发
cat "$CG/memory.events.local"

# 读取当前用量和两道内存边界,单位通常为字节
printf 'current='; cat "$CG/memory.current"
printf 'high='; cat "$CG/memory.high"
printf 'max='; cat "$CG/memory.max"

# 记录关键进程的 cgroup 归属,避免把别的服务计数算进来
cat /proc/"$PID"/cgroup

上面的命令只展示读取接口。若 memory.events 的 high 很高,而 memory.events.local 较低,优先检查后代服务是否在制造压力;若两者都高,再看当前 cgroup 自己的限制和进程归属。

memory.events、memory.events.local、memory.current 与进程 cgroup 归属的排查关系图
图2:统计归属排查结构图,连接层级事件、本地事件、当前用量和进程归属;这是原创说明图,不是终端截图。

按组合选动作:三种常见结果不要混为一谈

只有 high 增长:说明工作负载频繁越过 memory.high。先比较 memory.current、memory.high 与请求延迟,检查缓存、批处理或并发峰值是否让软边界过紧;如果业务可以承受更高峰值,再评估提高软边界或优化峰值分配。

oom 增长但 oom_kill 暂时不变:说明分配已经走到硬限制附近,但不代表一定已经杀进程。检查分配重试、调用方是否允许 OOM killer、限制值是否作用在预期层级,并结合服务日志判断请求是否失败。

oom 和 oom_kill 一起增长:按实际进程退出处理。记录被杀进程、父子进程关系、服务管理器的重启原因和 cgroup 层级;如果是多进程服务,还要确认主进程与 worker 是否属于同一个工作负载。不要只把 memory.max 调大而跳过泄漏、缓存和批量峰值的排查。

决策表:什么时候调 high,什么时候处理 max

现象首要判断建议动作
high 持续增加,oom 为 0软边界造成节流回收查延迟、回收频率和工作集,必要时调整 memory.high
max、oom 增加,oom_kill 为 0硬边界附近出现分配失败风险查 memory.max、分配重试和请求失败日志
oom_kill 增加已有进程被 OOM killer 处置保留 PID、归属、退出原因并检查恢复策略
层级 high 高、本地 high 低压力主要来自后代 cgroup逐级读取 memory.events.local,定位实际产生者

最后记住三个边界:事件计数器是累计值,不是实时用量;层级文件可能包含后代贡献,不等同于本地事件;high 是节流与回收信号,oom 才表示分配已经逼近失败。按这三点读取,基本就能避免把性能问题误判成 OOM,或把真实 OOM 当成普通内存抖动。

相关问题

high 增长是不是说明内存泄漏?

不一定。它只能说明使用量越过 memory.high 并触发了节流回收,可能来自合法的工作集、缓存或瞬时并发峰值。要判断泄漏,还要观察 memory.current 的长期趋势和分配来源。

oom 增长后一定会看到 oom_kill 吗?

不一定。oom 记录的是达到限制且分配即将失败的事件,最终可能表现为分配失败、重试或 OOM killer 处置;只有真的杀掉进程时,oom_kill 才会随之增加。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>