当前位置:首页 > 文章列表 > 文章 > linux > Linux cgroups v2 内存 怎样处理

Linux cgroups v2 内存 怎样处理

来源:17golang原创 2026-10-22 10:10:42 0浏览 收藏

Linux cgroups v2 内存问题,先不要把所有现象都叫作“内存不够”。正确的处理顺序是:先读 memory.current 建立当前用量,再用 memory.high 施加可恢复的回收压力,最后用 memory.max 作为硬边界;出现变慢、回收或进程被杀时,再结合 memory.events 和 memory.stat 判断原因。

这篇文章解决三个判断
  • memory.high 超限通常意味着回收和限流,不等于 OOM。
  • memory.max 是硬上限,无法回收到边界内时才会在该 cgroup 内触发 OOM。
  • memory.events 看事件,memory.stat 看构成,两者要和当前用量一起读。
cgroups v2 内存当前用量、high 限流和 max 硬边界的静态结构图
图1:cgroups v2 内存控制的静态说明图,展示 current、high 与 max 的边界关系,不是运行截图。

一、先区分当前用量和限制动作

排查一个 cgroup 的内存问题,第一组指标应该固定下来:memory.current 表示该 cgroup 及其后代当前使用的内存总量;memory.high 是超过后施加重回收压力的阈值;memory.max 是无法回收到边界内时触发 cgroup 内 OOM 处理的硬上限。三者的职责不同,不能只看一个数字下结论。

下面的例子假设工作负载位于 /sys/fs/cgroup/demo-worker。命令只展示读取和配置路径,实际操作前应确认该目录属于统一层级且当前进程具有相应权限。

# 先记录当前用量和两个边界,避免只凭进程 RSS 猜测
cg=/sys/fs/cgroup/demo-worker
printf 'current='; cat "$cg/memory.current"
printf 'high='; cat "$cg/memory.high"
printf 'max='; cat "$cg/memory.max"

# 记录事件快照,后续调整后用同样的字段做前后对比
cat "$cg/memory.events"
cat "$cg/memory.stat" | sed -n '1,20p'

基线至少保存两次:一次在业务平稳时,一次在症状出现时。若 current 接近 high 但 max 还很远,重点应放在回收压力和吞吐下降;若已经反复触碰 max,才进入硬上限排查。

二、用 memory.high 处理可恢复的压力

memory.high 更适合作为第一道治理边界。工作负载超过它时,内核会让该 cgroup 承受直接回收和限流压力,但这个边界本身不会调用 OOM killer。它的价值是给监控和管理程序留出时间:降低并发、释放缓存、迁移任务或回滚配置。

例如,先把测试工作负载的高水位设为 768 MiB,再观察事件和延迟变化:

# 设定可恢复的高水位;写入前确认这是测试或已批准的 cgroup
echo 768M > "$cg/memory.high"

# high 超限通常会增加 high 计数,用它和业务延迟一起判断是否过紧
grep -E '^(high|max|oom|oom_kill) ' "$cg/memory.events"

# 若需要撤销高水位,max 表示不设置这个边界
echo max > "$cg/memory.high"

如果 high 持续增长、请求延迟上升但 oom_kill 没有变化,典型解释是高水位过低或工作负载本来就需要更大的活跃集。此时应结合业务延迟、吞吐和回收行为逐步上调,而不是直接把 high 与 max 设成同一个值。

三、用 memory.max 设置最后一道边界

memory.max 解决的是“这个工作负载最多允许占用多少内存”。当使用量达到它且无法继续回收时,OOM 处理会被限制在对应 cgroup 的资源域内;在某些分配和并发时刻,观察到的用量也可能短暂超过该值。因此它是安全兜底,不是精确的实时仪表盘。

# 先保留一个比 high 更高的硬边界,避免回收压力立即演变成 OOM
echo 1G > "$cg/memory.max"

# 调整后同时观察当前用量和 OOM 相关事件
cat "$cg/memory.current"
grep -E '^(max|oom|oom_kill|oom_group_kill) ' "$cg/memory.events"

# 发生误配时可恢复为无限制,但这不是替代容量规划的长期方案
echo max > "$cg/memory.max"

下调 memory.max 时不要把“写入成功”当作“工作负载已经稳定”。内核还需要回收,无法满足边界时可能发生 OOM;生产环境应先通过 memory.current、事件计数和应用级错误率确认回滚窗口,再改变硬限制。

四、通过 memory.events 和 memory.stat 定位原因

读事件时,先看 high、max、oom 和 oom_kill。其中 high 增长说明曾经超过高水位并受到压力;max 增长说明触及硬边界;oom 说明发生了 OOM 处理尝试;oom_kill 则表示实际杀死进程的次数。若使用了 swap,还应注意相关 swap 事件字段是否增长。

memory.events 是层级统计,后代 cgroup 的事件也可能反映在上层;需要只看当前 cgroup 的本地事件时,可读取 memory.events.local。这能避免把子服务的压力误归因给父目录。

memory.events 与 memory.stat 联合定位 cgroups v2 内存问题的静态结构图
图2:从事件计数和内存构成定位问题的静态说明图,不是终端截图,也不代表已运行的测量结果。
# 先看层级事件,再看本地事件,区分父 cgroup 与当前目录的影响
cat "$cg/memory.events"
cat "$cg/memory.events.local"

# 按键读取构成,不依赖字段在文件中的固定顺序
awk '$1 == "anon" || $1 == "file" || $1 == "shmem" || $1 == "slab" {print}' "$cg/memory.stat"

如果 anon 占比高,通常要回到应用堆、线程栈或匿名映射寻找增长点;如果 file 占比高,则要判断文件缓存是否符合工作负载预期。memory.stat 的键可能随内核版本增加,脚本应按键查找,不要依赖固定行号。

五、把配置落成可回滚的排障步骤

  1. 先保存平稳期和异常期的 memory.current、memory.events、memory.stat。
  2. 只调整 memory.high,观察回收压力、延迟和 high 计数,确认是否是软边界过紧。
  3. 确认工作负载的合理峰值后,再把 memory.max 放在高水位之上作为最终保护。
  4. 出现 OOM 时,用 oom_kill 和本地事件确认杀进程发生在哪个 cgroup,再回到 anon、file 等构成字段。
  5. 每次只改一个边界,并保留可执行的回滚命令;不要把临时解除限制当成长期修复。

最常见的误区是把 memory.high 当成“超过就杀进程”,或把 memory.current 当成“应用真正需要的内存”。前者会导致告警和动作设计错误,后者会让缓存型工作负载被过度扩容。把边界、事件和构成放在同一张指标面板上,才能判断是配置问题还是应用增长问题。

相关问题

memory.high 超过后一定会 OOM 吗?

不会。它主要触发回收和限流,应该先关注延迟、吞吐和 high 事件。

为什么 memory.current 可能短暂超过 memory.max?

内核文档允许某些情况下出现临时超额,不能把一次读数直接当成稳定状态。

memory.events 和 memory.events.local 选哪个?

要看当前目录及后代的累计影响时看前者;只定位当前 cgroup 本地事件时看后者。

memory.stat 为什么不能按第几行解析?

字段是按键组织的,内核可能在中间增加新键,脚本应按字段名匹配。

资料依据:https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Linux systemd 环境文件权限 怎样处理Linux systemd 环境文件权限 怎样处理
上一篇
Linux systemd 环境文件权限 怎样处理
Linux find 大小时间 怎样处理
下一篇
Linux find 大小时间 怎样处理
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之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模型性能。
    587次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    624次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    658次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    626次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    442次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码