ARTICLE DETAIL

资讯详情

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

Linux free命令实战:从基础参数到内存排查与监控

Linux free命令实战:从基础参数到内存排查与监控 排查服务器内存问题的时候我第一个敲下的命令永远是free -h。这个命令在 Linux 系统管理里看着不起眼但它能回答一个最核心的问题内存到底够不够用。如果你只是把输出里的两个数字拿出来看大概率会和内存问题的真相擦肩而过。今天这篇就是纯实战向的 free 命令内容从基础参数讲到底层原理再配合真实排查场景把常见坑一个个掰开说清楚。我见过不少新人一看free输出里 used 占了很大比例就慌了急着找进程杀、重启服务结果折腾一圈发现问题根本不在那儿。Linux 的内存管理机制和 Windows 那一套完全是两回事理解 free 的输出先要理解内核怎么看待空闲内存。这篇文章适合刚入门的运维、做后端开发的工程技术人员也适合所有被内存告警吓过的朋友。1. 先搞清楚 free 命令到底解决什么问题1.1 为什么排查内存时第一个想到 freefree命令来自 procps 工具包它的核心功能只有一个读取/proc/meminfo这个虚拟文件里的内存统计信息然后按照人类比较容易阅读的格式打印出来。命令本身不发起任何系统调用去探测内存它就是一个格式化读取器所以它的性能开销几乎为零哪怕在高负载的机器上连续执行也完全没有压力。这给我们的第一个启发是free 看到的数据是内核视角的内存快照而不是某个进程的内存占用。当你执行free -h的时候得到的是整个系统范围内所有 CPU 节点合计的内存状态。它不关心哪个进程吃了多少内存只告诉你内存这个池子现在有多少水、多少可以马上用、多少被当作缓存占着但可以回收。传统运维习惯里登录任何一台 Linux 服务器第一步往往就是先跑一下free -h。原因很简单CPU 高了你还能靠负载均值慢慢分析磁盘满了你能靠 df 快速定位但内存一旦出问题往往表现为应用直接被内核杀掉OOM Killer或者系统开始疯狂交换导致整体卡顿反应时间非常短。先用 free 大致判断内存水位是成本最低的起步动作。1.2 free 与 top、ps、vmstat、htop 的分工有人会问我用top也能看到内存用htop还能看到彩色进度条为什么还要单独学 free我举个例子你就明白了。top默认界面里那个KiB Mem行用的数据源和 free 一样但呈现方式被压缩在一行里信息密度太低。真正的区别在于top擅长看过程比如哪个进程在吃 CPU、哪个进程内存涨得快适合动态观察ps aux --sort-%mem擅长看某一瞬间所有进程的静态快照可以快速找出内存占用最高的进程列表vmstat 1擅长看内存换入换出si/so和 CPU 等待适合定位交换带来的性能下跌free擅长给出一个干净利落、无干扰的整体内存结论而且非常适合写进脚本做监控判断。我在实际工作中通常的节奏是收到内存告警先free -h看整体水位如果 available 还充足那说明告警阈值设置可能不合理根本不用紧张若 available 很低再用ps aux --sort-%mem找出大户继续用top或pidstat观察该进程的实时变化。free 永远是第一个命令因为它能最快帮你确定问题是否真的存在。2. 基础用法与常用参数实战2.1 不同单位显示与最常用组合先看最基本的用法free直接回车默认以 KB其实是 KiB1024 字节为单位显示数字大得惊人基本没有可读性。所以日常操作首选-h参数让系统自动按人类易读的单位MiB、GiB输出。free -h输出大概是这样的total used free shared buff/cache available Mem: 31Gi 12Gi 5.2Gi 312Mi 14Gi 18Gi Swap: 31Gi 0B 31Gi这个输出包含了 Mem物理内存和 Swap交换空间两大部分。Mem 行里除了总内存和实际使用外buff/cache 指的是内核用作缓存的内存available 是真实可用的内存这个后面我会重点讲。参数方面常用的就这么几个参数作用使用场景-h自动以人类易读的单位显示日常查看首选-m以 MiB 为单位显示脚本统计、整数计算时用-g以 GiB 为单位显示看大内存服务器粗略水位-s 秒数每隔 N 秒刷新一次持续性观察内存变化-c 次数与-s配合指定刷新次数采样一段时间后自动退出-t在末尾多显示一行总计Mem 与 Swap 合计-w宽模式把 buff/cache 拆成 buffers 和 cache 两列深入分析缓存组成-l显示低内存和高内存统计老式 32 位内核环境我自己最常用的命令组合是free -h和free -m。前者看整体情况后者用于脚本里做数值比较。需要注意一点-m在较新的 procps 版本里实际含义是 MiB不是 MB如果脚本里按 1000 进制去转换算出来的结果会有约 2% 的偏差。严格要求的场景可以加--si参数强制使用 1000 进制但绝大多数运维场景用 1024 进制反而更符合内核实际计算方式。2.2 连续监控与脚本化输出内存问题往往是瞬时的比如某个定时任务瞬间申请大量内存你手动跑一次free -h可能根本抓不到峰值。这时候就要用-s连续刷新的功能# 每 3 秒刷新一次总共打印 10 次 free -h -s 3 -c 10这个命令会一直输出直到达到 10 次后自动退出。如果我不想频繁敲命令直接用 watch 包裹效果更好watch -n 2 free -hwatch 的好处是屏幕会原地刷新不会像-s那样刷屏适合挂在终端页面实时观察。不过要注意连续监控时终端里看到的数字是快照内存每一瞬间都在变化遇到主要内存波动要到同一时刻把 free 和进程列表抓下来对比否则容易误判。脚本化的时候我一般只提取关键字段。free 输出的第一行一般以Mem:开头第二行是Swap:。用 awk 可以直接抓走# 提取总内存和可用内存单位 MiB free -m | awk /^Mem:/{print total $2, available $7}这里$7对应 available 列只有带 available 的新版本才适用。如果是老版本内核或者老 procps 包输出里根本没有 available 列脚本需要注意兼容这个坑我在下面的章节会专门说。2.3 老版本与新版本输出的差异free 命令从 procps-ng 3.3.9 版本开始输出格式有了一个重大变化新增了 available 列同时把原来的-/ buffers/cache行去掉了。如果你维护的是 CentOS 6、Ubuntu 14.04 这样的老系统执行free -m看到的是下面这种格式total used free shared buffers cached Mem: 3210 2980 230 10 180 1800 -/ buffers/cache: 1000 2210 Swap: 1023 0 1023老格式里没有 available判断可用内存要看-/ buffers/cache行的 free 列也就是去掉 buffers 和 cached 后真正可以被程序使用的内存。这个设计容易让人困惑但它的逻辑是buffers 和 cached 都是内核可以随时回收来给应用程序用的所以不应算作已使用。打补丁后的新格式把 buffers 和 cache 归并到 buff/cache 列又增加了 available 列。available 比freebuff/cache更准确因为它考虑了内核需要保留的一部分内存比如 page cache 写回前的脏页不能无限回收是内核专门计算出来的预估可用值。日常判断服务器内存够不够用我只看 available 这一列这是全文最重要的一句结论。3. 输出结果深度拆解3.1 每一列分别代表什么拿新格式的第一行来说total used free shared buff/cache available Mem: 31Gi 12Gi 5.2Gi 312Mi 14Gi 18Gitotal物理内存总量等于内核配置的内存减去一部分内核自身保留区域通常比物理条标称值略小。used已经被占用的内存量。它的计算公式是used total - free - buff/cache这里注意used 是扣掉缓存后的结果不是进程实际占用的总和。free完全未被使用的内存也就是 page 处于 free 状态的页数。这个数字小不代表内存紧张因为 Linux 内核的理念是闲着就是浪费空闲内存会尽量被拿去当缓存。sharedtmpfs临时文件系统等共享内存占用的部分。在容器环境里这个值经常被忽略但 tmpfs 确实会消耗物理内存。buff/cache块设备缓冲buffers和页面缓存cache、slab 等合计。这部分内存貌似被占实际上在内核需要时可以回收。available预估的可用内存公式大致是MemFree Buffers Cached SReclaimable - 内存水位线。这是最贴近你现在能放心用多少内存的数字。Swap 行的含义更直观total 是交换空间总量used 是已经换出的页占用的空间free 是剩余空间。Swap 使用长期接近总量往往说明物理内存确实吃紧或者存在内存泄漏。3.2 buff/cache 的底层原理很多人对 buff/cache 的认知停留在这是缓存可以清理的层面但真要理解它需要聊几句内核的存储机制。buffers 和 cache 本质上是两类不同的东西。buffers 是块设备缓冲记录的是直接读写块设备时的元数据或原始块数据比如你格式化文件系统、读取 superblock 的时候数据会先经过 buffers。cache 则是文件数据的页面缓存page cache进程读取文件时内核会把文件内容缓存在内存里下次读同样的内容直接命中内存速度比磁盘快几个数量级。这两者并不严格区分很多情况下会互相转换所以 procps 在新版本里干脆把它们合并成一个 buff/cache 列。要拆开看用free -w宽模式free -w -h输出里会分成buffers和cache两列。此外/proc/meminfo里还有 SReclaimable可回收的 slab 内存等细节。slab 是内核用来管理对象的内存池比如文件索引节点inode、目录项dentry都需要小的对象分配这部分内存通常也包含在 cache 列统计里。到这里你应该明白一件事buff/cache 大并不等于内存不够它是内核为了让系统跑得更快主动做的投资。free 和 available 低而 buff/cache 大恰恰说明文件读写多、缓存利用率高通常不是坏事。3.3 available 列为什么最值得关注拿前面那个例子来说total 31Gifree 只有 5.2Gi但 available 是 18Gi。如果不懂的人看到 used 12Gi、free 5.2Gi可能直接判断内存已经用了 80%但实际上有 18Gi 可以马上给新程序用。服务器实际的内存压力远没有表面数据那么高。内核计算 available 时会考虑缓存可回收性干净的 cache 页可以直接回收脏页需要先写回磁盘才能回收正在使用的匿名页进程堆栈不可回收。所以 available 比单纯 freecache 更贴近真实可用量。这也是为什么监控系统、容器调度器比如 Kubernetes 节点压力驱逐底层用的都是这个值。我个人判断生产服务器内存是否健康的经验值是available 占总内存比例低于 20% 时开始警惕低于 10% 时属于高危状态。这时候再看 Swap 的使用情况如果 Swap 也在涨说明内存压力已经真实传导到交换层需要尽快处理。4. 实战场景与问题排查4.1 场景一新服务器内存占用率居高不下我接过不少这样的运维求助新部署的机器刚开机没有任何业务进程free -h一看used 已经占了 60% 以上问是不是被挖矿程序入侵了。遇到这种情况先不要慌。首先执行top -bn1 | head -20看看到底哪些进程占内存。大概率你会发现占用最多的进程名是 mysqld、java、nginx 之类的正常业务进程或者就根本没几个进程。其次用free -w看 buffers 和 cache 的分布如果 cache 很大说明系统在启动过程和文件读取中已经把大量页面缓存加载好这是正常现象。真正需要注意的是另一种情况系统刚启动就 used 很高进程列表却空空如也。这时候检查一下是不是有进程把内存消耗在共享内存里了按之前说的看 shared 列再用ipcs -m检查共享内存段。另外内核参数vm.nr_hugepages如果配置了大页内存HugePages 会直接从物理内存里划走free 命令的 total 会变少这部分开销 top 的进程列表里也看不出来。我遇到过一次某台数据库服务器配置了 64 个 1GB 的大页物理内存直接被吃掉 64G怎么看怎么内存不够实际就是大页配置导致的。4.2 场景二判断内存是否真的不够用云计算环境中经常收到内存充足已用 95%的告警登录进去看 free 输出却是一切正常。这种告警偏差往往是因为监控系统用了错误的指标——它计算的是used / total而不是基于 available 计算。正确判断内存够不够用的方法三步走看 available 绝对值free -m看 Mem 行的 available 列比如只看剩下 500M那确实紧张看 Swap 使用趋势连续执行free -s 5几次如果 Swap 的 used 值持续攀升说明物理内存不足匿名页在持续被换出看内存是否有突发增长结合进程维度ps aux --sort-%mem | head -n 5看是哪个进程在吞内存。用 available 判断还有一个好处它天然考虑了缓存回收的代价。比如你启动一个需要 10G 内存的新应用available 只有 8G那内核回收缓存的过程中可能伴随大量磁盘写回应用启动会明显变慢但不会直接 OOM。available 低于需求但不触发 OOM 时表现就是系统响应变慢却不报错这种慢但不挂的状态在排查时最容易被忽略。4.3 场景三Java 进程内存占用疯涨Java 应用是内存问题大户特别是堆外内存、线程栈、元空间这些部分用ps看 RSS 和 free 报告的对不上很常见。排查时我一般先执行ps aux --sort-%mem | head -n 5看 Java 进程的 RES 列再对比 JVM 的-Xmx参数。如果 JVM 堆最大是 4G进程 RSS 却涨到了 8G那说明多出来的部分在堆外DirectByteBuffer、线程栈、JIT 代码缓存、Metaspace 都算。这时候 free 只能告诉你系统层面的内存少了定位具体是哪一块需要配合jcmd、jstat或者 NMTNative Memory Tracking工具。还有一种情况是连接池、线程池配置太大。曾经有个服务线程池最大 500 个线程每个线程栈默认 1M光线程栈就有 500M加上连接缓冲内存涨得飞快。从 free 看到 available 不停往下掉再通过top -Hp PID看到线程数量暴增最终定位到配置问题。这类问题不是内核故障是应用对内存的使用方式出了问题free 的价值在于快速抛出内存水位异常这个信号。4.4 场景四做一条简单的内存水位监控脚本与其等告警后手忙脚乱不如自己写个脚本定时监控。下面这个小脚本是我常用的模板逻辑很简单每 5 分钟检查一次 available 占比低于 20% 时记录到日志低于 10% 时发送告警消息。#!/bin/bash # 内存监控脚本检查 available 比例异常时记录与告警 # 需要 root 权限执行建议配合 crontab 每 5 分钟运行一次 LOG_FILE/var/log/memory_monitor.log THRESHOLD_WARN20 THRESHOLD_CRIT10 # 读取内存数据单位 MiB MemTotal$(free -m | awk /^Mem:/{print $2}) MemAvailable$(free -m | awk /^Mem:/{print $7}) if [ -z $MemTotal ] || [ -z $MemAvailable ]; then echo $(date %Y-%m-%d %H:%M:%S) free 命令输出解析失败 $LOG_FILE exit 1 fi UsedPercent$(( (MemTotal - MemAvailable) * 100 / MemTotal )) echo $(date %Y-%m-%d %H:%M:%S) 内存使用率: ${UsedPercent}% (available: ${MemAvailable}M) $LOG_FILE if [ $UsedPercent -ge $((100 - THRESHOLD_CRIT)) ]; then echo CRITICAL: 内存严重不足当前使用率 ${UsedPercent}% $LOG_FILE # 这里可以接企业微信、钉钉或邮件接口 elif [ $UsedPercent -ge $((100 - THRESHOLD_WARN)) ]; then echo WARN: 内存使用率偏高当前使用率 ${UsedPercent}% $LOG_FILE fi配合 crontab 使用*/5 * * * * /usr/local/bin/memory_monitor.sh注意脚本里用$7拿到 available 列老版本 free 没有这一列脚本会解析失败这个判断我在脚本里做了兜底。强烈建议在脚本开头做兼容检查否则老系统上定时任务会静默失败监控等于白做。5. 常见问题与避坑经验5.1 典型问题速查表现象可能原因排查方向free 命令不存在procps 包未安装根据发行版安装 procps 或 procps-ng脚本取不到 available 列procps 版本过老改用 free -mused 很高但 available 充足缓存占用正常用free -w分看 buffers 与 cacheSwap used 持续上涨物理内存不足或泄漏结合进程 RSS 和 free 趋势定位系统内存总量比物理条少内核保留、大页配置检查/proc/meminfo中 HugePages_Total所有进程内存之和远小于 used共享内存、内核 slab 或 DirectMap检查 shared 列、slabtop、/proc/meminfofree 显示 total 变少了memory hotplug 或内核 memblock 保留检查 dmesg 中的内存信息每个问题的处理方式都不一样但第一步永远是同一个动作确认 free 输出里 available 的绝对值。大多数内存报警最后都止步于这一步——available 还很健康报警阈值该调。5.2 几条独家实战心得第一条不要一看到 buff/cache 高就忙着清缓存。sync echo 3 /proc/sys/vm/drop_caches这个操作在排查问题时可以临时做一次但是清完缓存后系统文件读取性能会短时下降而且下次读写又会重新缓存治标不治本。我见过有人把 drop_caches 写进定时任务理由竟然是让 free 显示好看点这是对内存管理机制最大的误解。缓存是内核自带的性能优化机制不是内存泄漏。第二条判断内存问题要把 free 和 vmstat 结合起来。vmstat 1里重点关注 siswap in和 soswap out两列如果这两列持续非零说明系统确实在频繁换页这是内存不足的实锤指标。free 本身不提供这个动态信息只看静态快照容易被瞬间数值误导。第三条容器环境里看 free 要谨慎。在容器内部执行 free看到的是宿主机的内存总览部分新内核已经做了隔离并不代表容器自身的配额。判断容器内存使用应该以 cgroup 的统计为准比如读/sys/fs/cgroup/memory.current或者用docker stats。如果容器里只有 free 可用至少要意识到它反映的是宿主机水位不是容器水位。第四条写脚本解析 free 输出时尽量用-m固定单位同时注意 procps 版本差异。我踩过最典型的坑是服务器从 CentOS 7 迁移到 Ubuntu 20.04免费的输出列数不一样老脚本里 awk 的$7取不到 available 直接取到了空值导致监控全部误报。这类问题务必要在代码里做字段存在性校验。最后再分享一个实用小技巧如果你需要记录某个时刻的内存快照做故障复盘可以直接把完整输出落盘free -h /tmp/memory_$(date %Y%m%d_%H%M%S).log多留几个时间点的快照排查内存泄漏问题时对比 available 的下降趋势比单看某个瞬间有用得多。内存问题很少是一下子炸掉的大多数情况下是缓慢爬坡能回看趋势曲线定位问题的时间能缩短一大半。
返回列表