ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Linux free命令全解析:从字段含义到内存水位判断与故障排查

Linux free命令全解析:从字段含义到内存水位判断与故障排查 服务器内存报警打开终端第一件事敲什么绝大多数人都会说是free -h。可你真的确信自己看懂了那七列数字吗我见过不少同行被 free 的输出带偏——明明物理内存还有几个 G 的 free业务却频繁 OOM也见过新手盯着巨大的 buff/cache 误以为内存泄漏差点把线上服务器的缓存全清掉。这篇实操篇就围绕 Linux 系统管理里最常用的 free 命令把字段含义、版本口径、真实水位判断、故障排查链路和监控写法一次讲清楚。适合刚入门 Linux 系统管理的运维新人也适合想把手里的内存监控做得更靠谱的开发者。1. 从free输出开始先把七列数字的真面目搞明白1.1 最常用的几种执行姿势free命令本身不复杂但执行参数选不对输出会把人看晕。我日常最常用的是这么几条free -h # 按人类可读单位显示GB/MB 级别日常查看首选 free -m # 固定按 MB 显示写脚本解析时比 -h 更稳 free -s 2 # 每 2 秒刷新一次适合观察短时波动 free -s 2 -c 5 # 每 2 秒刷新一次一共输出 5 次适合采样 free -w # 宽模式把 buff 和 cache 拆成两列看明细时用 free -t # 额外显示一行物理内存与 swap 的总计注意-s和-c一般是配合使用的单独用-s会一直刷屏终端里看个几秒就得手动 CtrlC。脚本采集场景我更推荐用-m配合 awk 去解析而不是解析-h的人类可读单位这一点到后面第四部分还会细说。1.2 字段逐个拆解used不等于应用占用的内存新版 Linux 系统上执行free -h输出大致长这样$ free -h total used free shared buff/cache available Mem: 7.6Gi 2.1Gi 3.2Gi 120Mi 2.2Gi 5.0Gi Swap: 2.0Gi 0Bi 2.0Gi这七列的含义我按自己的理解重新翻译一遍total物理内存总量注意这个值一般会小于你买内存条的总容量原因放到第五部分讲。used已经被进程占用的物理内存。这里的“已用”要特别小心它已经扣除了 buff/cache 部分指的是真正属于应用和内核核心逻辑的内存。free完全没被用到的内存。这一列的数字在 Linux 上通常不会很大而且经常被新手误读。shared共享内存主要是进程间通信使用的内存另外/dev/shm这种 tmpfs 文件系统占用的内存也可能会计入 shared。buff/cache磁盘缓冲和页缓存这是 Linux 内存管理里最大的“蓄水池”后面专门讲。available估算的“当前还能启动新应用的内存”。内核会综合 free、缓存可回收程度、swap 空闲情况等因素给出一个相对保守的估计值。你如果把这七列加起来会发现一个矛盾total远大于used free因为中间还坐着 buff/cache 这个大家伙。老教程里常说“Linux 会把所有空闲内存拿去做缓存”指的就是这一列。1.3 新旧版本输出口径差异这个坑必须先排掉我早期看 CentOS 6 上跑 free输出跟现在不一样这就是网上很多旧文章能把你带沟里的原因。老版本 free 输出是这个样子$ free -m total used free shared buffers cached Mem: 7824 4430 3394 120 210 2120 -/ buffers/cache: 2099 5724 Swap: 2047 0 2047老版本里的used是包含 buff/cache 的所以看起来内存用了 4430MB实际上真正被应用占用的只有下面-/ buffers/cache那行的 2099MB。新版本procps-ng 3.3.10 之后直接去掉了-/ buffers/cache这一行把 used 改成不包含 buff/cache 的“净使用量”并且增加了 available 列。所以你现在看到的used已经不是旧文章里说的那个 used 了。这是一个特别容易让人算错内存使用率的点。判断你的 free 是旧口径还是新口径除了看有没有 available 列还可以执行free -V看 procps-ng 版本号。写脚本解析数据时我强烈建议直接绕过 free 命令本身去读/proc/meminfo这个文件里的字段是内核直接提供的不随 procps 版本变化后面会给出具体脚本。2. 真正的内存水位为什么buff/cache巨大反而是好事2.1 buff和cache分别是谁为什么会占这么多内存很多新手看到 buff/cache 占了总内存的一半以上第一反应是“内存泄漏了”。其实恰恰相反这是 Linux 内存管理的正常状态某种程度上还是性能好的表现。简单说buff是对块设备磁盘的缓冲比如你往磁盘写数据数据会先攒在缓冲区里再批量落盘cache是文件页缓存你读过的文件内容会被留在内存里下次再读同一个文件时直接命中内存速度能快几个数量级。内核的做法就是“内存闲着也是闲着不如拿来缓存磁盘 IO”所以系统跑得越久buff/cache 越大是正常的。只要这些缓存是可回收的它就不是“被占用”更像是“预支的复用空间”。当某个新应用突然申请大块内存时内核会自动回收一部分缓存还给应用不需要人工干预。这也是 available 这个指标存在的意义——它扣除了不可回收的部分给出一个更真实的“可用内存”估值。2.2 判断内存是否紧张的黄金标准是available我在团队里带新人时反复强调一条原则别盯着 free 列先看 available。free 列只是完全没分配出去的物理页但 Linux 不会让这些空闲页长时间闲着它会拿去做 page cache所以 free 列小不代表内存紧张。反过来available 才是内核估给你的“现在还能吃下多少新应用”的答案。比如一台 8G 内存的服务器free 可能只有 300MB但 available 有 6.2G这种情况下你尽管放心部署新服务。真正要紧张的是 available 持续走低。怎么量化我一般看 available 占 total 的比例available / total 30%安全随便跑。20% ~ 30%关注尤其是高峰时段再观察。10% ~ 20%预警排查是否存在内存占用异常进程。 10%告警这时候 swap 大概率已经在工作了随时可能触发 OOM。这是经验阈值数据库类、JVM 类业务可以根据实际情况调但判断逻辑是通用的先看 available再看 used最后才看 free。2.3 一键水位判断两个版本的脚本示例如果你懒得每次都人肉估算可以直接在终端里跑一段 awk我自己最常用的是基于/proc/meminfo的版本awk /^MemTotal:/{t$2} /^MemAvailable:/{a$2} END{availa*100/t; printf MemTotal%.2fG MemAvailable%.2fG AvailableRatio%.1f%%\n, t/1048576, a/1048576, avail; if (avail 20) print WARN: available memory below 20%} /proc/meminfo这样输出一行类似MemTotal7.62G MemAvailable5.03G AvailableRatio66.0%的结果一眼就能判断水位。为什么不用 free 命令去解析因为 CentOS 6 等老系统的 free 输出没有 available 列而/proc/meminfo里的 MemAvailable 是内核自己算好的不依赖 procps 版本兼容性最好。如果你所在的系统内核太老/proc/meminfo里连 MemAvailable 都没有比如内核 2.6.32 那一代那就只能用近似公式MemFree Buffers Cached。注意这个估算值会偏乐观因为有一部分 cache 是不可回收的临时看个大概可以别拿它做精确监控。3. 真实故障场景下free的排查链路3.1 场景一swap打满系统卡顿这是线上最常见的“内存危机”。现象是系统负载不高但 ssh 敲命令明显迟滞free -h里 swap 已经用掉一多半甚至全满。排查链路我习惯这么走先free -h确认物理内存和 swap 的整体水位。再vmstat 1连续看几次重点看si和so两列。这两个数值持续大于 0说明内核正在频繁地把内存页换到 swap、又把 swap 页换回内存这就是系统卡顿的直接原因。用ps aux --sort-%mem | head -8找出内存占用最高的进程。定位到进程后判断是业务正常增长还是异常泄漏再决定是重启服务、扩容内存还是优化业务配置。处理时有个小技巧如果短时间内没法扩容可以先临时把 swappiness 调低让内核尽量别用 swapsysctl -w vm.swappiness10这只是缓兵之计治标不治本。swap 打满本质上说明物理内存已经进入慢性耗尽状态长期方案永远是加内存或者给大内存应用设置合理上限。3.2 场景二free显示内存足够业务却OOM比 swap 打满更诡异的场景是你执行free -havailable 明明还有 3G但容器里的 Java 应用还是被 OOM Kill 了。问题在于free 看的是宿主机整体内存而业务进程所在容器有自己的 cgroup 限额。排查这类问题我一般按下面顺序查# 先看进程真实位于哪个 cgroup 并读取内存限额 cat /proc/pid/cgroup cat /sys/fs/cgroup/memory/容器对应的cgroup路径/memory.limit_in_bytes # 如果是 docker 容器直接看 docker stats 也行 docker stats container_namecore 场景里cgroup 限制往往是“元凶”宿主机内存没满但容器的 memory.limit 已经打满触发容器级别的 OOM进程被杀宿主机 free 却一切正常。所以以后看到业务 OOM 先别急着怀疑 free 输出去看 cgroup 的限制值。另一个容易踩的坑是内存超卖。如果内核参数vm.overcommit_memory被设成了 2系统会按 CommitLimit 限制所有进程的内存申请总量这时在/proc/meminfo里查看Committed_AS和CommitLimit两个字段你会发现提交出去的内存已经逼近甚至超出限额。这种情况下进程可能 malloc 内存直接失败表现和 OOM 很像但 free 只看物理内存是看不出门道的。3.3 场景三进程内存不断上涨疑似泄漏这种问题一般出现在应用运行一段时间后。现象是used持续上升available稳步下降重启进程后能缓解但过几天又涨回来。排查时先别急着定性为内存泄漏要排除“缓存型增长”。很多正常进程比如 Redis、MySQL、JVM会把内存当作缓存或堆空间来用涨到某个业务水位后稳定住这叫合理占用。真正的泄漏是RSS 只涨不跌而且没有任何业务增长逻辑支撑。定位进程靠这一条命令就够ps aux --sort-%mem | head -8--sort-%mem按内存占用从高到低排序配合head直接看前几名。想观察进程内存的实时变化可以用 pidstatpidstat -r -p pid 1如果确认是泄漏重点查这几处Java 应用查堆配置和 GC 日志Python 应用查循环引用和全局容器C/C 应用查内存释放链路。free 在这一阶段的作用就是帮你确认“系统还在漏”真正定位还是得靠进程级工具。4. 从手动敲命令到无人值守free的周期输出与组合监控4.1 watch与-s选项让内存数字自己动起来手动敲 free 只能看到当下那一刻的快照排查内存波动时需要观察变化趋势。最简单的方式是配合 watchwatch -n 2 -d free -h-n 2表示每 2 秒刷新一次-d会高亮显示两次刷新之间发生变化的部分哪个数字在动一眼就能看出来。这个组合我用的频率非常高尤其是观察内存缓慢上涨时高亮的效果能让你直接锁定趋势。如果不想用 watchfree 自己也支持周期输出free -s 5 -c 3 -h每 5 秒输出一次一共输出 3 次后自动退出。这种固定次数的采样方式适合放在脚本里做短时采集比 watch 更好控制结束时机。4.2 与top、ps、vmstat联动从系统级盯到进程级free 解决的是“系统整体水位”问题一旦发现水位异常马上要从进程维度找原因。我常打的组合拳是free -h ps aux --sort-%mem | head -8 vmstat 1三件事并行先看整体水位再看哪个进程最吃内存最后看 swap 换入换出是否频繁。还可以顺手开 top进入交互界面后按M让进程按内存排序按E切换显示单位人工观察几轮刷新。需要注意ps里的%MEM是 RSS 除以物理内存总量得出的百分比和 free 里的used是两个口径。一个进程的 RSS 很小但虚拟内存巨大在 free 里看不出来但在排查内存泄漏时反而值得留意。4.3 落盘采样与告警一份能直接套用的内存监控脚本生产环境我建议直接接入 node_exporter 这类监控但手动排查时还是需要一个能落盘采样的脚本。下面这个写法简单且不依赖额外工具#!/bin/bash # 每 1 秒采样一次共采样 60 次适合短时波动排查 for i in $(seq 1 60); do now$(date %F %T) line$(awk /^MemTotal:/{t$2} /^MemAvailable:/{a$2} END{printf total%.2fG avail%.2fG ratio%.1f%%, t/1048576, a/1048576, a*100/t} /proc/meminfo) echo $now $line /tmp/mem_sample.log sleep 1 done跑完看/tmp/mem_sample.log里的 ratio 列如果它是平滑下降说明内存确实在被持续消耗如果忽高忽低可能是应用内存抖动可以结合业务日志再看。要写告警阈值的话我自己的经验值是available 占比低于 20% 触发关注低于 10% 触发告警持续 5 分钟低于 5% 就要准备人工介入了。注意别把阈值卡得太死业务尖峰期短暂跌破 20% 很常见关键是看恢复速度。5. free背后的数据源与我的几条经验5.1 free读取的其实是/proc/meminfo以及total为什么偏小free命令本身不探测硬件它只是/proc/meminfo的“翻译官”。内核在/proc/meminfo里实时维护着内存统计数据free 读取后按人类友好的格式展示给你。想验证的话很简单两个命令对照看grep -E MemTotal|MemFree|MemAvailable|Buffers|Cached|SwapTotal|SwapFree /proc/meminfo free -h两边数据能对上。这就是为什么我前面一直建议脚本直接读/proc/meminfo——少一层 procps 版本的转换就少一层兼容性风险。还有一个常见疑问明明服务器插了 8G 内存free里的 total 却只有 7.6G少的几百兆去哪了一部分被内核自身保留比如启动参数里 crashkernel 预留的内存一部分被固件、显卡显存或虚拟机 Hypervisor 占用。这是正常现象不值得惊慌。5.2 踩过几次坑之后的几条实用建议最后分享几条我自己踩坑换来的经验都跟 free 的实操有关。第一日常查看就用free -h但脚本解析一定要用free -m或直接读/proc/meminfo。-h输出的 Gi/Mi 对人类友好对 awk 却是灾难你会发现解析出来的数字全是小数单位还不统一。第二判断内存紧张程度只看两个指标available和swap。available 低是内存不够swap 持续换页是内存正在被榨干这两个信号比 used 数值更有说服力。第三容器环境看 free 要留个心眼。容器里执行 free 看到的是宿主机的/proc/meminfo不是容器 cgroup 的限制值所以容器内内存满了但 free 还显示挺闲是正常的。看容器真实内存占用优先用docker stats或直查 cgroup 文件。第四排查 OOM 不要只盯着 free 输出记得看内核日志dmesg -T | grep -i out of memory|killed process这段日志会直接告诉你哪一时刻哪个进程因为内存紧张被杀比对着 free 猜要高效得多。我自己现在排查内存问题的顺序已经固定了线上出报警先free -h确认水位再看dmesg有没有 OOM 记录找不到就直接进/proc/meminfo和 cgroup 目录里翻最后才是上进程级工具。free 能帮你快速定位方向但真正找到根因还得靠组合命令一起发力。这套流程走过几十次之后你对“内存到底够不够”的判断会远比只看第一眼 free 输出要准。
返回列表