cgroup v2 memory.high怎么配置或排查
很多运维和开发同学刚接触cgroup v2的时候,经常碰到memory.high参数配置完没效果,或者业务进程没到硬限制就被触发内存回收的情况,顺着常规配置步骤和排查路径走,基本都能定位到问题。
配置cgroup v2的memory.high前要先确认当前系统已经启用cgroup v2统一层级,排查时优先核对当前cgroup目录下的内存统计项、当前触发的水位阈值,再逐层校验父cgroup的配置继承规则即可。
如果服务进入 cgroup v2 后只是变慢,却没有被 OOM 杀掉,先看 memory.high。它是“超过后施加回收压力并节流”的边界,默认值是 max;真正的硬内存上限是 memory.max。因此排查重点不是盯着一个剩余内存数字,而是确认进程归属、当前用量、high 事件以及内存压力是否同时出现。
memory.high超限会让该 cgroup 承受直接回收和节流,通常不会直接触发 OOM killer。- 直接写 cgroup 文件时使用字节数;例如 512 MiB 应写成
536870912,不是带单位的字符串。 memory.events.local看本组,memory.events还会包含子树;两者都要和memory.stat、memory.pressure对照。
memory.high 控制的是节流,不是 OOM
Linux 内核把 memory controller 的几个边界分成了不同职责。memory.low 和 memory.min 是回收保护,memory.high 是超限后的节流边界,memory.max 才是无法回收时可能进入 cgroup OOM 的硬限制。把二者混用,是“服务没有退出却延迟暴涨”这类现象最常见的起点。
| 接口 | 作用 | 排查时关注什么 |
|---|---|---|
memory.high | 超过后加大回收压力并节流 | memory.events(.local) 的 high |
memory.max | 无法回收时限制用量,可能触发 OOM | max、oom、oom_kill |
memory.current | 当前 cgroup 及其后代的内存用量 | 是否持续越过 high 边界 |
这也解释了一个容易误判的结果:memory.current 高于 memory.high 并不等于设置失败。高边界允许在极端情况下被暂时突破,关键证据是工作负载是否被持续节流,以及事件计数是否增长。
先把 memory.high 写进正确的 cgroup
先确认统一层级和控制器是否可见,再确认目标 PID 的归属。下面的示例只针对已经存在的 cgroup v2 挂载点;变量写法方便在测试机上替换目录,不要把宿主机根 cgroup 当成业务组直接修改。
# 确认 cgroup v2 挂载点和 memory 控制器是否可见
CG=/sys/fs/cgroup/demo-app
test -f /sys/fs/cgroup/cgroup.controllers || { echo "不是预期的 cgroup v2 根目录"; exit 1; }
grep -qw memory /sys/fs/cgroup/cgroup.controllers || { echo "memory 控制器不可用"; exit 1; }
# 直接写入 cgroup 文件时使用字节数:512 MiB = 536870912 字节
HIGH_BYTES=$((512 * 1024 * 1024))
printf '%s\n' "$HIGH_BYTES" | sudo tee "$CG/memory.high" >/dev/null
cat "$CG/memory.high"
# 先确认目标进程确实属于该组,再观察它的后续行为
PID=12345
grep -q "0::/demo-app" "/proc/$PID/cgroup" || { echo "PID 不在目标 cgroup"; exit 1; }
printf '%s\n' "$PID" | sudo tee "$CG/cgroup.procs" >/dev/null
如果 memory.high 不存在,通常不是“参数拼错”,而是 memory 控制器没有在父级的 cgroup.subtree_control 中启用,或者目标目录不是你以为的 v2 层级。cgroup v2 的控制器启用遵循自上而下的约束,先看 cgroup.controllers 和父目录的 cgroup.subtree_control,再处理权限。

memory.events 和 PSI 怎么定位瓶颈
设置完成后不要只重复读取阈值。memory.current 回答“现在用了多少”,memory.events.local 回答“本组发生了什么”,memory.stat 帮你拆分匿名内存、文件缓存、内核和 socket,memory.pressure 则反映任务因内存不足而等待的压力。
# 读取同一 cgroup 的用量、局部事件和压力;命令只读不修改配置
CG=/sys/fs/cgroup/demo-app
printf 'memory.current='; cat "$CG/memory.current"
printf '\nmemory.high='; cat "$CG/memory.high"
printf '\nmemory.max='; cat "$CG/memory.max"
# local 只看本组,memory.events 则可能包含后代 cgroup 的计数
cat "$CG/memory.events.local"
# 按键名读取统计,避免依赖 memory.stat 的显示顺序
awk '$1 ~ /^(anon|file|kernel|sock|shmem)$/ { print }' "$CG/memory.stat"
cat "$CG/memory.pressure"
判断可以按这个顺序进行:如果 memory.current 接近或超过 memory.high,同时 memory.events.local 的 high 增长,说明本组确实反复进入高边界节流;如果只有 memory.events 增长而 local 不变,优先检查子 cgroup。若 max、oom 或 oom_kill 增长,问题已经越过 memory.high,应该回到 memory.max 与工作负载峰值排查。
memory.stat 还能缩小方向:anon 持续上升更像进程堆或匿名映射增长,file 偏高则要看页缓存和 tmpfs,kernel、sock 异常时不要只调高应用阈值。PSI 的 some 或 full 持续升高,才说明节流已经转化为可感知的等待;单独一次 high 计数不能代表服务一定需要更多内存。

常见问题
memory.high 可以直接写 512M 吗?
直接写 cgroup v2 接口时按内核文档使用字节数,建议先用 shell 算出整数再写入。systemd 的 MemoryHigh=512M 属于上层配置语法,不能据此推断底层文件也接受相同单位。
为什么 memory.current 超过 memory.high 还没有被杀?
这是预期语义。memory.high 主要触发回收压力和节流,不负责直接调用 OOM killer;需要硬上限时才检查 memory.max,并同时观察 oom 相关事件。
应该读 memory.events 还是 memory.events.local?
要判断当前目录自身,优先读 local;要观察整棵子树,读 memory.events。两者的层级口径不同,混着比较会把子服务的 high 事件误算到当前服务。
实际调参时,先记录业务低峰和峰值下的四组证据,再逐步调整 memory.high;不要用一次偶发计数替代持续压力判断。若由 systemd 管理服务,还应把 unit 的 MemoryHigh/MemoryMax 与实际 cgroup 文件对应起来,避免运行时手改被下一次部署覆盖。
Go http.CookieJar 出错时怎么排查域匹配
- 上一篇
- Go http.CookieJar 出错时怎么排查域匹配
- 下一篇
- Go deferclose 出错时怎么查清理错误
-
- 文章 · linux | 1小时前 | Linux · systemd · EnvironmentFile ·
- systemd EnvironmentFile 多行变量如何保留空格与换行
- 186浏览 收藏
-
- 文章 · linux | 3小时前 |
- systemd socket activation怎么配置或排查
- 245浏览 收藏
-
- 文章 · linux | 8小时前 |
- Linux ss 看不到监听端口时先查哪个 namespace
- 492浏览 收藏
-
- 文章 · linux | 10小时前 | Linux · 运维排障 · tmpfs · df tmpfs Linux临时文件系统
- Linux tmpfs 满了但磁盘空间还有为什么
- 204浏览 收藏
-
- 文章 · linux | 14小时前 | Linux · systemd · 运维排障 · systemd journalctl Linux日志 journald
- journald 如何按服务和启动批次筛选日志
- 371浏览 收藏
-
- 文章 · linux | 16小时前 |
- systemd timer OnCalendar 如何避免重复触发
- 144浏览 收藏
-
- 文章 · linux | 17小时前 |
- systemd service Restart=always 为什么导致失败循环
- 167浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 110次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 25次使用
-
- OpenCompass
- OpenCompass是上海AI实验室推出的开源大模型评测平台,提供CompassKit、CompassHub和CompassRank三大核心组件,支持LLM及多模态模型的一站式标准化评估与排行榜查询。
- 44次使用
-
- AGI-Eval
- AGI-Eval是由上海交大等高校联合发布的大模型评测社区,提供公正透明的LLM能力榜单、多领域评测集及Data Studio数据服务,助力AI模型性能评估与NLP科研开发。
- 25次使用
-
- SuperCLUE
- SuperCLUE是权威的中文大语言模型综合评测基准,涵盖语言理解、知识应用、AI Agent智能体及安全性等12项核心能力。通过多轮对话与客观测试,定期发布榜单与技术报告,为模型研发、优化及行业选型提供科学依据。
- 264次使用
-
- Linux vmstat 如何分辨内存抖动与磁盘等待:si、so、wa 与复测顺序
- 2026-08-30 501浏览
-
- Linux搭建vsftpdFTP服务器教程
- 2026-04-30 501浏览
-
- Shell脚本安装教程:.sh一键安装指南
- 2026-03-16 501浏览
-
- Linux清空文件内容的几种方法
- 2025-12-01 501浏览
-
- Linux命令行下载文件技巧
- 2025-11-23 501浏览

