Linux内存管理详解:free、vmstat、buff/cache、swap

「服务器内存快满了!」------这是运维群里出现频率最高的一句话,也是误报率最高的一句话。因为很多人只看 free 的 free 列,没搞清 buff/cache 和 available 的区别,把健康的机器当成内存泄漏来排障。这一篇把 free、vmstat、buff/cache、swap 讲清楚,看完你就能准确判断:到底是真的内存不够,还是 Linux 在「合理利用」。

一、free:看一眼内存全貌

语法格式

复制代码
free [选项]

常用参数

参数 说明
-h 人性化单位(GiB/MiB),最常用
-m / -g 以 MB / GB 为单位
-s 秒 每隔 N 秒刷新一次
-t 多一行显示总计

示例与预期输出

复制代码
free -h

预期输出:

复制代码
               total        used        free      shared  buff/cache   available
Mem:           7.6Gi       3.1Gi       512Mi        20Mi       4.0Gi       4.1Gi
Swap:          2.0Gi       128Mi       1.9Gi

逐列读懂:

列 含义
total 物理内存总量
used 已用(= total - free - buff/cache)
free 完全空闲的内存,这个数字小很正常
shared 共享内存(tmpfs、shm)占用
buff/cache 内核缓冲区 + 页缓存,可回收
available 估算的真正可用内存,最重要

结论先行:判断内存是否紧张,看 available,不看 free。

二、buff/cache:不是「被吃掉」,是「被借用」

Linux 的设计哲学是:空闲的内存是浪费的内存 。所以内核会把所有暂时不用的内存拿来缓存磁盘数据(page cache)和块设备元数据(buffer cache),这就是 buff/cache。

关键在于:这部分内存随时可以被回收。当应用需要内存时,内核优先把 cache 里的页面释放出来给它。所以:

  • free 列很小 → 正常,内存被有效利用了
  • buff/cache 很大 → 好现象,说明读磁盘命中缓存多了
  • available 很小 → 这才是真信号

available 是内核综合「free + 可回收的 cache」给出的估算值。它大,说明真要起来还能挤出内存;它小,说明可回收的都回收得差不多了,再来应用就得动 swap 或触发 OOM。

想看 cache 的构成

复制代码
grep -E "Buffers|Cached|MemAvailable|Dirty" /proc/meminfo

Buffers:            156384 kB
Cached:            3856212 kB
Dirty:               12048 kB
MemAvailable:      4218364 kB
  • Buffers:块设备元数据缓存
  • Cached:文件内容的页缓存
  • Dirty:被改过但还没写回磁盘的页,这个数持续增长要警惕
  • MemAvailable:available 的原始值

三、vmstat:一行看全 VM / IO / CPU

free 只看内存,vmstat 一次给你内存、分页、IO、CPU 全景,是排查性能问题的一把好手。

语法格式

复制代码
vmstat [间隔秒] [次数]

常用参数

参数 说明
1 5 每秒采样一次,共 5 次
-s 显示内存统计汇总
-d 显示磁盘统计
-w 宽格式输出,防止列被挤在一起

示例与预期输出

复制代码
vmstat 1 5

预期输出:

复制代码
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 1  0  131072 524288 156384 3856212  0    0    12    45  250  480  6  2 91  1  0
 0  0  131072 520000 156400 3857000  0    0     0    60  240  460  5  2 93  0  0

各列含义(重点标出):

列 含义 判断
r 运行队列长度(等 CPU 的进程数) 持续 > 核心数,CPU 紧张
b 处于不可中断睡眠的进程数 持续 > 0,可能 IO 卡住
si / so 换入/换出 swap 的量(KB/s) 持续非 0 = 内存不足
bi / bo 块设备读/写(KB/s) 看磁盘活跃度
in / cs 中断数 / 上下文切换数 cs 异常高看中断或锁
us/sy/id/wa 用户/系统/空闲/IO 等待占比 wa 高 = 磁盘瓶颈

⚠️ 最关键的判断:si/so

si 和 so 长期为 0 ,说明内存够用,swap 没被真正使用。

si/so 持续大于 0,说明物理内存不够了,系统在「颠簸」(thrashing)------反复把页换出换入硬盘,性能断崖式下跌。

看到 swap 里「有数据」不等于「在用 swap」。判断 swap 是否被高频使用,看的正是 si/so,不是 free 里 swap 的 used。

四、swap:不是「内存不够」的罪证

swap 是磁盘上的一块交换空间。它的作用有两个:

  1. 给内核留缓冲:把长期不访问的匿名页换出去,腾出物理内存。
  2. 应对突发峰值:短时内存冲高,先换一些出去扛过去。

合理的 swap 使用是健康的。真正要警惕的是高频换页 (si/so 持续非 0),因为磁盘比内存慢好几个数量级,一旦高频换页,系统基本就废了。

swappiness:调节换页倾向

复制代码
cat /proc/sys/vm/swappiness

默认通常 60。含义是「内核有多倾向于把匿名页换出」:

  • 60:比较积极,普通桌面/通用服务器
  • 10:低,数据库服务器常用(数据库自己有缓存,不想要内核乱换)
  • 0:除非内存真的要用光,否则不换

临时调整:

复制代码
sudo sysctl vm.swappiness=10

永久生效写入 /etc/sysctl.conf:

复制代码
vm.swappiness = 10

⚠️ 要不要关掉 swap

  • 不要直接 swapoff -a:真到内存峰值时,没有 swap 缓冲会直接触发 OOM 杀进程。
  • 数据库主机可以降低 swappiness(如 1~10),但保留一定 swap 作保险。
  • Kubernetes 节点 traditionally 禁用 swap,因为调度器假设内存是独占的(新版支持 swap 但需配置)。

五、内存告急的完整排查路径

真遇到内存问题,按这个顺序走:

复制代码
# 1. 看总量和可用量
free -h

# 2. 看是否高频换页
vmstat 1 5

# 3. 找出吃内存最多的进程
ps aux --sort=-%mem | head -10

# 4. 看内核 slab 缓存是否异常(内核对象泄漏)
sudo slabtop -o | head -15

# 5. 看共享内存段
ipcs -m

# 6. 看是否有大量脏页未回写
grep -E "Dirty|Writeback" /proc/meminfo

⚠️ 常见错误

  1. 看到 free 小就重启服务 。free 小 + available 大是健康的,重启服务反而清空了 cache,让后续读盘变慢。
  2. 把 buff/cache 当泄漏 。它是可回收的,不是应用吃的。真要看应用内存,用 ps 的 RSS 或 smem 看 PSS。
  3. 误判 swap 使用 。free 里 swap used > 0 不代表正在颠簸,必须结合 vmstat 的 si/so 看。
  4. 只盯单一进程忘了内核 。slab 缓存(Slab)异常增长也是内存消失的常见原因,slabtop 要会用。
  5. 没配 swap 却说「内存够」 。没 swap 时,available 逼近 0 会直接触发 OOM,没有缓冲余地。

六、原理探究:页缓存、脏页与回写

理解内存管理,绕不开 页(page)。Linux 以 4KB 为基本单位管理内存(大页场景为 2MB 或 1GB),所有内存操作都围绕页展开。

page cache 是怎么来的

你 cat bigfile 或程序 read() 文件时,数据不是直接从磁盘进应用缓冲区,而是:

复制代码
磁盘 → 页缓存(page cache) → 应用缓冲区

第一次读文件,数据被读进 page cache,同时拷给应用。再读同一文件,直接从 cache 返回,不碰磁盘 。这就是「第二次读文件飞快」的原因,也是 buff/cache 不断增长的来源。

脏页与回写

应用 write() 文件时,数据先写进 page cache,标记为 dirty(脏页) ,然后立即返回------写操作并没有立刻落盘 。内核的**回写线程(kworker/flush)**会在稍后把脏页批量刷到磁盘。

这带来两个后果:

  • 性能好:写入合并、批量落盘,减少磁盘次数。
  • 有两个坑 :
    1. 断电丢数据 :未回写的脏页断电就没了。所以重要数据要 fsync()。
    2. 脏页堆积 :写入速度远超磁盘回写速度,脏页越积越多,/proc/meminfo 里 Dirty 暴涨,内核会开始强制同步回写,导致写操作突然变慢(这就是「写风暴」)。

关键内核参数

复制代码
sysctl vm.dirty_ratio vm.dirty_background_ratio
参数 默认 含义
vm.dirty_background_ratio 10 脏页占比超过它,后台开始回写
vm.dirty_ratio 20 超过它,进程写操作被阻塞,强制回写
vm.dirty_expire_centisecs 3000 脏页超过 30 秒强制回写

理解这两个阈值,就能解释「为什么大量写文件时程序会突然卡一下」------正好撞上了强制回写。

七、OOM Killer:最后的手段

当内存和 swap 都用尽,内核会启动 OOM Killer ,挑一个进程杀掉。选谁下手看 oom_score:

复制代码
cat /proc/<PID>/oom_score
cat /proc/<PID>/oom_score_adj

oom_score 越高越容易被杀。你可以手动调整倾向:

复制代码
echo -1000 > /proc/<PID>/oom_score_adj   # 尽量别杀它(需 root)

-1000 表示「永不杀」,1000 表示「优先杀」。关键服务可以设低,防止被误杀。

看 OOM 日志

复制代码
dmesg -T | grep -i "out of memory"
journalctl -k | grep -i oom

日志里会写清楚「killed process XXX (total-vm...)」,这就是定位内存事故的现场记录。

八、几张表总结

free 列速查:

列 该不该担心
free 小 不担心
buff/cache 大 不担心
available 小 担心
swap used 大但 si/so 为 0 不担心
swap used 大且 si/so 持续非 0 担心

内存指标一句话记忆:

  • 看内存够不够 → available
  • 看有没有颠簸 → vmstat 的 si/so
  • 看谁吃的 → ps 的 RSS / smem 的 PSS
  • 看内核吃的 → slabtop、/proc/meminfo
  • 看写压力 → /proc/meminfo 的 Dirty/Writeback

内存是 Linux 最容易被误解的子系统。记住核心一句:Linux 会把空闲内存用到极致,free 少不代表内存不够,available 才是你要盯的数字。

相关推荐
_不会dp不改名_1 小时前
leetcode_3727 最大平方交替和
linux·算法·leetcode
Lsetea1 小时前
OpenSSL报certificate revoked:error 23与CRL吊销层级排查
linux·https·ssl证书·openssl·crl
4SAPI1 小时前
多模型API调用实战:一个项目接入GPT、Claude和DeepSeek
linux·人工智能·gpt·php
j7~2 小时前
【仿 RabbitMQ 项目】发布订阅消息队列 (篇八):交换机数据管理模块,分层类设计、SQLite 回调原理与代码实现
服务器·网络·数据库·消息队列·交换机·交换机数据管理·sqlite回调原理
电梯界知识分子2 小时前
浙江台州六层拆迁自建房:建房前期土建交底,规避薄墙预制板误区,预留轮椅通行电梯
运维·服务器·网络·安全·家用电梯
Escalating_xu2 小时前
【Linux 网络编程】UDP Socket 编程(下):回调封装、网络字典与多线程聊天室
linux·网络·udp
看-是灰机2 小时前
Milvus向量数据库
linux·运维·人工智能·机器学习·milvus
weixin_446260852 小时前
PromptAgent‑Eval:面向提示驱动智能体的细粒度自动化评测框架
运维·自动化
下辈子不要当码农2 小时前
Linux驱动学习(1)
linux·运维·学习