容器内存看着够用却 OOM?先别信 free,去读 cgroup

举报
yd_242458115 发表于 2026/11/08 13:09:16 2026/11/08
【摘要】 free 和 nproc 在容器里经常显示宿主机数据。这篇讲清真实配额在哪三个文件里、memory.current 为什么虚高、OOM 之后怎么用退出码和 memory.events 确认是谁杀的,以及跑大任务前怎么估算峰值。

先说结论

容器里 free -h 显示的不是你能用的内存,而是宿主机的内存。真实上限在 cgroup 的 memory.max 文件里。判断"这个任务能不能跑"之前,先去读那个文件,而不是看 free。

一、为什么会误判

free 读的是 /proc/meminfo,nproc 读的是 /proc/cpuinfo。容器(namespace)默认不隔离这两个文件,除非额外挂了 lxcfs 之类的工具去伪造。

所以会看到很荒诞的场景:free -h 报几百 GB 内存、几十个核,实际配额只有几十 GB、十几个核。程序按"还剩一大半空闲"去规划内存,然后在看起来最安全的时候被 OOM kill。

二、三个必读文件(cgroup v2)

文件 | 含义

/sys/fs/cgroup/memory.max | 硬上限,写着 max 表示不限

/sys/fs/cgroup/memory.current | 当前用量(包含 page cache)

/sys/fs/cgroup/memory.events | oom / oom_kill 计数

cat /sys/fs/cgroup/memory.max
cat /sys/fs/cgroup/memory.current
grep -E '^(oom|oom_kill)' /sys/fs/cgroup/memory.events

cgroup v1 的老机器路径不一样:/sys/fs/cgroup/memory/memory.limit_in_bytes。判断版本看 stat -fc %T /sys/fs/cgroup,返回 cgroup2fs 就是 v2。

三、memory.current 高不等于要 OOM

memory.current 把 page cache 也算进去了。跑完一次大文件读操作,current 可能贴着 max,但只要内存可回收,内核会自己腾出来。

要判断"真实占用",去 memory.stat 里看:

grep -E '^(file|inactive_file|anon) ' /sys/fs/cgroup/memory.stat

粗略换算:实际匿名内存 ≈ anon,可回收缓存 ≈ file。真正会把你顶到 OOM 的是 anon 部分。

四、CPU 同理,也在 cgroup 里

cat /sys/fs/cgroup/cpu.max

两个数字:配额 周期。比如 1500000 100000 表示每 100ms 周期里有 1.5 秒 CPU 时间,也就是 15 核。写 max 100000 才是不限。

五、OOM 之后怎么确认到底是谁杀的

1. 退出码 137 = 128 + SIGKILL,被强杀的典型特征(SIGKILL 的编号是 9,128+9=137)

2. memory.events 里的 oom_kill 计数增加了

3. dmesg | grep -i oom —— 真正的 kill 日志在宿主机侧,容器内经常看不到

4. 平台控制台可能只回一句"内存溢出,请检查代码或增加配置",不给任何数字

所以关键是自己提前算好峰值,别等平台来告诉你。

六、算峰值再决定跑不跑

  • 先量小的:拿数据量缩到 1/10 的用例跑一遍,记录峰值
  • 量两个数:/usr/bin/time -v 里的 Maximum resident set size,或者采样 memory.current
  • 再外推:按数据量线性放大,留 30% 余量
  • 先看常驻:如果"任务峰值 + 常驻服务占用"已经接近 memory.max,正确做法是先停常驻服务再跑,而不是赌调度运气

七、一个高频踩法

压测脚本自己读 free 判断"还有几百 GB 空闲",据此决定并发数,结果一开满就被 kill——因为它读的那份数据是假的。

改法有两种。第一种,让脚本自己算真实余量:

LIMIT=$(cat /sys/fs/cgroup/memory.max)
CUR=$(cat /sys/fs/cgroup/memory.current)
AVAIL=$(( (LIMIT - CUR) / 1024 / 1024 ))
echo "真实可用约 $AVAIL MB"

第二种更省事:把上限当参数从外部传进来,脚本不再自己探测。

小结

容器里别信 free 和 nproc;memory.max 才是权威;判断 OOM 靠退出码 137 + memory.events + 宿主机 dmesg。算清峰值再跑,比跑崩了再猜便宜得多。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。