看懂 Linux 内存:free 里的 buff/cache 到底是什么

举报
yd_292915714 发表于 2026/11/06 18:24:10 2026/11/06
【摘要】 free 显示内存快满了其实不是故障。解释 buff/cache 的作用、怎么用 available 判断真实余量、容器里为什么要看 cgroup,以及 drop_caches 为什么线上不能随便用。

看懂 Linux 内存:free 里的 buff/cache 到底是什么

很多人第一次看 free -h 都会被吓一跳:机器明明只跑了几个小服务,used 却快占满了,free 只剩几百 MB。其实这是 Linux 内存管理的正常表现,问题出在对 buff/cache 的理解上。

free 的每一列在说什么

              total        used        free      shared  buff/cache   available
Mem:           7.8Gi       2.1Gi       412Mi        18Mi       5.3Gi       5.2Gi
Swap:          2.0Gi          0B       2.0Gi
  • total:物理内存总量,扣除内核和硬件保留的部分
  • used:已经分配出去的内存,total - free - buff/cache
  • free:完全没被使用的内存
  • shared:tmpfs 和共享内存占用
  • buff/cache:块设备缓存(buff)+ 文件页缓存(cache)
  • available:真正还能给新进程用的内存估算值,这才是该看的数

关键结论:判断内存够不够,看 available,不要看 free。

buff/cache 不是"被占用",是"被借用"

Linux 的设计哲学是"空闲的内存就是浪费的内存"。读过的文件内容会留在 page cache 里,下次读同一个文件直接命中内存,不用再走磁盘。写操作也会先进 page cache,由内核择机回写。

这些缓存页有个特点:它们是可回收的。当有新进程申请内存、而空闲内存不足时,内核会扫描并释放一部分干净的缓存页(脏页要先回写)。所以 cache 占得多不代表内存紧张,available 已经把可回收的部分算进去了。

一个常见的误解是"cache 太高导致 OOM"。实际上 OOM 发生时,内核已经把能回收的缓存都回收过了,真正卡住的是不可回收的部分:匿名页(进程堆栈)、内核 slab、共享内存、locked 页。

怎么确认到底是谁在吃内存

按可疑程度排序,几个实用命令:

1. 按 RSS 排序看进程

ps aux --sort=-rss | head -15

注意 RSS 会把共享库重复计算,多个同类进程(比如多个 JVM)加起来可能超过物理内存,这不算错。

2. 看 PSS,比 RSS 准

sudo smem -t -k -p | tail -20

PSS 把共享页按共享者数量均摊,多进程场景下更接近真实占用。没有 smem 时可以读 /proc/<pid>/smaps_rollup 里的 Pss。

3. 看内核 slab 占用

sudo slabtop -o | head -20

dentry 和 inode 缓存过大(常见于遍历过海量小文件的机器)会吃掉几个 GB,而且这部分在 free 里算作 cache,但回收速度不如 page cache 快。

4. 看有没有内存泄漏趋势

while true; do free -m | awk 'NR==2{print $3, $7}'; sleep 60; done

used 持续单调上升、available 持续下降,且没有对应的业务量增长,才可能是泄漏。偶发上涨后回落属于正常波动。

主动释放缓存:能做,但基本不该做

网上流传的"释放内存"命令:

sync
echo 3 | sudo tee /proc/sys/vm/drop_caches

它确实能把 cache 清空,free 立刻变好看。但代价是接下来所有文件读取都要重新走磁盘,数据库和 Web 服务的响应时间会明显抖动。除非在做性能基准测试、需要可复现的冷启动数据,否则不建议在线上执行。

如果确实需要限制缓存规模,正确做法是调内核参数,而不是手工清空:

# 降低脏页在内存中停留的倾向(默认 20%,写多场景可降到 10)
sudo sysctl -w vm.dirty_ratio=10

# 提高内核回收 cache 的积极程度(默认 100,越大越积极)
sudo sysctl -w vm.vfs_cache_pressure=200

容器环境要额外注意

在 Docker / Kubernetes 里,free 显示的是宿主机的内存,不是容器的限额。容器实际受限的是 cgroup:

cat /sys/fs/cgroup/memory.max          # cgroup v2 上限
cat /sys/fs/cgroup/memory.current      # 当前用量
cat /sys/fs/cgroup/memory.stat | grep -E '^(file|anon|slab)'

memory.current 里包含 page cache,所以容器里 cache 高但没触顶是正常的;一旦 memory.current 接近 memory.max,内核会先回收 cache,回收不动才触发 cgroup OOM Killer。

排查容器被 OOM 杀时,dmesg 里能看到明确记录:

dmesg | grep -i 'killed process'
# Memory cgroup out of memory: Killed process 12345 (java) total-vm:...

看到这条就说明是 cgroup 限额,不是宿主机内存不够——这时调大 limit 或者降 JVM 堆才对,清缓存没用。

小结

  • free 小、buff/cache 大是 Linux 的正常状态,不是故障
  • 判断内存压力看 available,不是 free
  • OOM 的根因通常是匿名页 / slab / cgroup 限额,不是 cache
  • drop_caches 能救急但不能治病,线上慎用
  • 容器里要看 cgroup 的 memory.current / memory.max,free 会骗人

理解这几条之后,再看监控面板上的内存曲线就不会慌了。

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

评论(0)

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

全部回复

上滑加载中

设置昵称

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

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

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