看懂 Linux 内存:free 里的 buff/cache 到底是什么
看懂 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会骗人
理解这几条之后,再看监控面板上的内存曲线就不会慌了。
- 点赞
- 收藏
- 关注作者
评论(0)