服务器内存不足排查:free 与 vmstat 判断真实占用并安全扩容

一台 Linux 服务器主机与堆叠内存条的占用监控示意插图

服务器半夜重启、网站间歇性卡顿、日志里冒出 Out of memory 报错——这些问题十有八九指向内存。但真正着手处理时,很多人会被一个现象误导:free -h 显示可用内存只剩几百 MB,于是立刻断定”内存不够,该升配了”。如何判断服务器内存是不是真的不够、瓶颈到底在哪里?本文帮你解决这个排查难题:先分清”真实占用”和”缓存假象”,再找出到底是谁在吃内存,最后才轮到扩容决策。文章按这三步展开,每一步都给出可以直接执行的命令和判断标准,帮助你在加钱升配之前先把问题看清楚。

第一步:用 free 区分真实占用与缓存假象

Linux 会把空闲内存拿来做磁盘缓存(page cache)和缓冲区,这部分随时可以回收,所以”available”才是判断内存是否紧张的正确指标,而不是”free”。看一组典型的输出:

free -h 显示 total 7.6G,free 只有 320M,但 available 还有 5.1G——这台机器一点都不缺内存,剩下的是缓存,业务需要时内核会立即释放。

真正需要警惕的信号是 available 长期低于总内存的 10%,或者 swap(交换分区,内存不够时把不活跃数据挪到磁盘的机制)的 used 列持续增长。swap used 增长比 available 更危险:说明内核已经开始把内存页换出,此时应用响应延迟会明显抖动,数据库类业务最先受影响。判断规则可以记成一句话:available 低但 swap 稳定为零,通常只是缓存水位高;available 低且 swap 在涨,才是真缺内存。

第二步:用 vmstat 看内存压力的变化趋势

free 是快照,vmstat(虚拟内存统计工具)能看到趋势,这正是排查服务器内存不足时两者的分工。关键命令:

vmstat 2 10 每 2 秒采样一次,连续看 20 秒。重点盯三列:si(换入)、so(换出)和 bo(块输出)。si、so 长期不为零,说明系统在频繁做内存与磁盘之间的页面交换,这是内存压力的直接证据;此时 CPU 的 wa 列(等待 I/O 时间占比)往往同步升高,应用卡顿的根源就找到了。

为什么要看趋势而不是快照?因为内存泄漏的典型形态是”缓慢爬升”:某应用每小时泄漏几十 MB,free 快照看不出异常,但把 vmstat 输出按小时对比,si/so 会从全零逐渐变成持续非零。我的测试环境里曾有一台 8G 内存的服务器,白天各项指标正常,凌晨三点定时任务触发一处泄漏代码后 so 列突然飙升,两小时内 4G 数据被换到磁盘,网站响应从 80ms 掉到 2 秒——这个模式只有趋势数据能暴露。类似这种”白天正常、夜间劣化”的现象,很多时候并非内存独有问题,也可能与共享资源争抢有关,可以结合影响 VPS 速度的核心因素一起分析,把 CPU、I/O 和内存三条线分开验证。

内存页与磁盘之间双向交换形成 swap 通道的示意插图

第三步:找出到底是谁在吃内存

确认存在真实内存压力后,下一步是定位具体进程,否则扩容只是把问题推迟。

从系统内存条中逐层定位占用进程的排查层次示意插图

按顺序用三条命令排查。先看总量排行:ps aux --sort=-%mem | head -10 列出吃内存最多的 10 个进程,多数情况到此就能锁定元凶。若怀疑泄漏,再对比该进程当前 RSS(常驻内存集,进程实际占用的物理内存)与刚启动时的数值,24 小时内单调增长且不回落,基本可以确认泄漏。最后查 OOM(Out of Memory,内核内存耗尽保护机制)的历史记录:dmesg -T | grep -i "out of memory" 或 journalctl -k --since "24 hours ago" | grep -i oom

OOM killer 的日志会明确写出”哪个进程、何时、被杀掉了多少内存”。很多”服务器半夜自己重启”的案例,真相就是某个进程内存失控后触发 OOM,且被杀的恰好是数据库或 PHP-FPM 这类核心服务。日志里如果频繁出现同一个进程名,即使当前内存够用,也应尽快修复或限制该进程,比如用 systemd 的 MemoryMax 给它设上限,防止它再次拖垮整台机器。数据库类业务的内存参数怎么配,可以参考这篇服务器配置与性能优化的分类文章,把 buffer pool 和连接数上限一起纳入检查。

第四步:扩容决策要先用压测验证

前三步做完,如果确认是业务增长带来的真实内存缺口(而不是泄漏或配置问题),才进入扩容环节。这里最常见的失误是”直接买更大的配置”,结果新机器上线后老问题依旧——因为瓶颈可能是 swap 配置不当或应用内存参数没调。

正确的顺序是先做一次压测,模拟业务高峰的内存水位。比如 WordPress 站可以用 ab -n 2000 -c 50 这类工具压一轮,同时开着 vmstat 2 观察 si/so:如果并发 50 时 swap 开始增长,说明当前配置撑不住峰值,扩容目标就是让峰值并发下 si/so 保持为零并留出 20% 以上的 available 余量。再核对应用侧参数:PHP-FPM 的 pm.max_children(最大子进程数)乘以单进程平均内存,MySQL 的 innodb_buffer_pool_size(InnoDB 缓冲池大小),这些参数不匹配时,升配的钱会大量浪费在闲置内存上。

总结与行动建议

服务器内存不足的排查可以收拢成一条链路:free 看 available 确认真假紧张,vmstat 看 si/so 确认压力趋势,ps 和 OOM 日志定位具体进程,压测验证后才做扩容决策。四步走完,绝大多数”内存不足”都能找到确切原因,而不是靠重启续命。

如果你需要一个资源配置透明、支持从虚拟主机平滑升级到独立服务器的方案,可以考虑 Hostease 的服务器产品线,各档位内存规格都有明确标注;日常运维中建议把 vmstat 和 available 的监控接进现有告警体系,阈值设为 available 低于 15% 或 si/so 连续 10 分钟非零,让内存问题在拖垮业务之前就被发现。更多服务器性能排查实践,也可以在服务器分类文章里继续查阅。

发表评论