news 2026/5/12 9:26:23

【云原生问题集】容器内存监控避坑:90%工程师踩过的“free命令雷区”

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【云原生问题集】容器内存监控避坑:90%工程师踩过的“free命令雷区”

你有没有遇到过这种怪事?

压测跑得好好的,容器突然被 OOM Kill 了。你赶紧进容器敲了个free -h,一看内存快吃满了,心想“资源不够,加!” 加完内存,跑一会儿又被杀了。

坑爹的是,你明明在 K8s 里给容器设了内存上限 2Gi,但free显示的却是宿主机的 64Gi 内存?而且 used 那列的数字远超 2Gi?

读完后你能搞懂:

  • 为什么容器里的free看到的是“假”内存
  • 页缓存(Page Cache)怎么把你给坑了
  • 内核回收页缓存的时间差为啥能杀人
  • 3 条命令精准看 cgroup 真实内存占用

一、先捅破这层窗户纸:free这命令在容器里就是“骗子”

我亲自踩过这个坑。那会儿刚上容器化,业务总在凌晨 OOM,监控显示容器内存 1.8Gi(上限 2Gi),但进容器一查free,used 高达 50Gi(宿主机的)。

关键点:free读的是/proc/meminfo,而/proc/meminfo从来都是节点的全局信息。不管你在不在容器里,它都返回整台物理机/虚拟机的内存数据。

# 进容器执行 $ free -h total used free shared buff/cache available Mem: 62Gi 28Gi 12Gi 1.2Gi 21Gi 31Gi

62Gi total?我容器明明只配了 2Gi 上限。这就离谱。

正确姿势:想看 cgroup 限制的真实内存,用cat /sys/fs/cgroup/memory/memory.limit_in_bytes(cgroup v1)或cat /sys/fs/cgroup/memory.max(cgroup v2)。

# cgroup v2(常见于新系统) $ cat /sys/fs/cgroup/memory.max 2147483648 # 2Gi,这才是真的上限

二、页缓存那点破事:它算使用量,但能回收

另一个常见误会:free里的used包含了页缓存。页缓存是啥?就是文件读写时内存里留的副本,目的是加速 I/O。

比如你容器里拷贝个大文件:

$ cp /data/bigfile /dev/null

执行完你再free,发现 used 蹭蹭涨。但这不是你程序泄漏内存,是系统拿空闲内存做了缓存。

内核的承诺:当程序真需要内存时,页缓存可以被回收。所以在 cgroup 统计里,页缓存默认算作“可回收”的内存。

但问题来了——回收需要时间。

我遇到过线上事故:一个 Java 应用突然申请 500Mi 内存,而此时容器空闲内存只剩 200Mi,剩下的 300Mi 全是页缓存。内核开始回收页缓存,但 IO 压力大,回收速度没跟上,两三秒后 OOM Killer 直接就把 Java 进程给砍了。

你猜怎么着?过了半分钟,页缓存回收完了,内存又富裕了。进程白死了。

三、亲手复现:用一段代码把容器搞 OOM

来,跟着我做。这是个最小复现案例。

前置条件:Docker 已装,最好有个测试环境(别在生产搞)。

1. 起一个带内存限制的容器

$ docker run -it --rm --memory=512m --memory-swap=512m alpine sh

设置了 512Mi 硬上限。

2. 看 cgroup 真实上限

# 容器内执行 $ cat /sys/fs/cgroup/memory/memory.limit_in_bytes 536870912 # 512Mi

3. 模拟页缓存填满

# 生成一个 400Mi 的文件 $ dd if=/dev/zero of=/tmp/bigfile bs=1M count=400 $ cat /tmp/bigfile > /dev/null & # 后台读,刷页缓存

4. 看内存占用(两种视角的差异)

# 假视角 - free $ free -m total used free shared buff/cache available Mem: 62785 28000 30000 200 4785 32000 # 这 total 明显是宿主机的 # 真视角 - cgroup 统计 $ cat /sys/fs/cgroup/memory/memory.stat | grep -E "^(cache|rss|total_rss)" cache 420000000 # 页缓存约 400Mi rss 51200000 # 常驻内存 50Mi

真正的内存压力要看rss + cache是否接近 limit。这里总占用约 450Mi,离 512Mi 还差一点。

5. 手动触发 OOM

# 再申请 100Mi 匿名内存(用 stress 或自己写个 malloc) $ dd if=/dev/zero of=/dev/shm/oom bs=1M count=100

如果在 cgroup 限制边缘,内核会先回收页缓存。回收不过来就杀进程。你可以dmesg看内核日志:

$ dmesg | tail -20 [12345.678] Memory cgroup out of memory: Kill process 1234 (dd) score 1000 or sacrifice child

四、怎么安全地看容器内存?我推荐这 3 条命令

命令1(最稳):cat /sys/fs/cgroup/memory/memory.stat+ 自己算

$ cat /sys/fs/cgroup/memory/memory.stat | awk '{if($1=="rss") rss=$2; if($1=="cache") cache=$2} END {print "真实使用量(MiB): "(rss+cache)/1024/1024}'

命令2(K8s 用户):kubectl top podkubectl top pod --containers

$ kubectl top pod my-app NAME CPU(cores) MEMORY(bytes) my-app 150m 438Mi # 这个已经是扣除可回收页缓存的数值

kubectl top拿的是 cgroup 的usage_in_bytes减去total_inactive_file(不活跃页缓存),比较贴近真实压力。

命令3(docker 用户):docker stats --no-stream

$ docker stats --no-stream CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O abc123 app 2.3% 438MiB / 512MiB 85.5% ...

它和kubectl top逻辑类似,已经帮你减掉可回收的 page cache。

我个人不推荐用free做任何容器内存监控,这命令在容器场景基本等于自欺欺人。

五、常见坑:明明内存没超,容器还是挂了

场景:你设了 limit 2Gi,监控显示 used 1.8Gi,但容器 OOM 了。

大概率原因:页缓存 + rss 超过 limit,但监控工具只看了 rss。

我见过挺多团队用ps的 RSS 累加或者top看 RES 列,这些都不包含页缓存。而你容器里跑了个日志采集,或者某个模块写临时文件,页缓存悄悄涨到了 500Mi,加上 1.8Gi 的 RSS 已经 2.3Gi 了,内核当然要杀人。

解决办法:监控系统要拉 cgroup 的total_rss + total_cache,或者直接用container_memory_working_set_bytes指标(Prometheus node_exporter 或 cAdvisor 都有)。

六、最后说几个实用建议(都是血泪教训)

  1. 告警阈值别设 95%——页缓存回收需要时间,留 20% buffer 吧,设到 80% 就该扩容了。
  2. 应用启动时预热会导致页缓存暴涨——比如 Java 类加载、Python 读一堆依赖文件。建议启动时预留额外内存,或者等稳定了再看监控。
  3. /proc/meminfo在容器不可信——任何时候都别用。用 cgroup 接口。
  4. OOM 后留现场dmesg看内核日志,docker inspect看退出码(137 就是 OOM kill)。

(顺便提一嘴,cgroup v2 的文件路径和名字变了,memory.limit_in_bytes改成memory.maxmemory.stat结构也略有调整。别在旧脚本上硬套。)

你遇到过因为看错free导致半夜起来加机器的经历吗?评论区聊聊。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/12 9:24:31

如何轻松下载B站8K超高清视频?哔哩下载姬完整解决方案

如何轻松下载B站8K超高清视频?哔哩下载姬完整解决方案 【免费下载链接】downkyi 哔哩下载姬downkyi,哔哩哔哩网站视频下载工具,支持批量下载,支持8K、HDR、杜比视界,提供工具箱(音视频提取、去水印等&#…

作者头像 李华
网站建设 2026/5/12 9:16:01

GPTMessage项目拆解:SwiftUI+Combine集成OpenAI与Hugging Face API实战

1. 项目概述与核心价值最近在折腾一个挺有意思的Side Project,一个叫GPTMessage的iOS/macOS应用。简单来说,它把ChatGPT的聊天能力、DALLE的图像生成,还有Hugging Face上的一些模型(比如图像描述、Stable Diffusion)给…

作者头像 李华
网站建设 2026/5/12 9:15:50

不用花一分钱!微信隐藏数据恢复教程,小白零基础也能会

谁还没遇到过这种糟心事?微信聊天记录悄悄丢失、重要图片被隐藏、过期文件打不开、误删好友聊天记录想找回,明明感觉数据还在手机里,就是找不到入口,去线下门店咨询,动辄就要收几百上千元恢复费,实在太不划…

作者头像 李华