系统故障玄学之内存明明显示空闲,服务器却频繁卡顿卡死?拆解被忽略的 Linux 隐性内存陷阱

做运维 18 年,见过太多人被 free -h 的输出误导。收到业务卡顿告警登录机器,第一指令敲 free,一眼看到剩余内存尚可,下意识排除内存问题,转头去排查 CPU、磁盘 IO,兜兜转转耗费大量时间,最后才发现病根依旧在内存。

这类故障有很强迷惑性:不会直接触发进程 OOM 杀死服务,而是持续性抖动、间歇性卡顿,时好时坏,难以稳定复现,非常容易被归为网络、业务代码问题。

一、先理清最核心误区:buff/cache 不等于可直接使用内存

先回顾 free 输出关键字段,很多人认知停留在几年前的旧思想。

bash

c 复制代码
free -h
  • total:总物理内存
  • used:已占用内存
  • free:彻底空闲、没有任何数据的裸内存
  • available:重点!应用程序真正能够申请到的内存

很多运维只看 free 列。Linux 内核会尽可能利用空闲内存用作 PageCache、Buffer,加速文件读写。这部分缓存可以回收,但回收存在成本,不是瞬间完成。当系统持续大量申请内存,内核需要频繁回收页面,如果回收速度跟不上应用分配速度,业务进程就会短暂阻塞,直观感受就是服务器卡顿。

关键结论:判断内存是否紧张,优先看 available,不要盯着 free。

二、造成 "内存看着空闲,机器持续卡顿" 四类典型场景

场景 1:available 持续走低,内核频繁回收页缓存

free 数值很大,但 available 持续偏低。新业务申请内存时,内核需要同步回收大量 pagecache,产生 CPU 开销、IO 抖动,引发业务短暂停滞。

场景 2:Swap 频繁读写(最常见)

物理内存尚有剩余,但系统一直在使用 Swap。常见诱因:swappiness 参数配置不合理;存在大量长期闲置内存,内核主动换出至 Swap。一旦进程需要重新访问这部分内存,触发磁盘 IO,延迟瞬间拉满。

bash

bash 复制代码
# 观察Swap交换波动
vmstat 1

si(换入)、so(换出)持续大于 0,就是危险信号。

场景 3:内存碎片严重

长期运行的服务器,频繁创建销毁进程、大量 mmap 操作,造成物理内存碎片化。系统拥有足够总空闲内存,却没有连续大块内存可供分配。应用申请大内存时分配失败、发生阻塞,严重时直接触发 OOM。

bash

bash 复制代码
# 查看内存碎片
cat /proc/buddyinfo

场景 4:透明大页 (THP) 引发系统卡顿

数据库、中间件服务器重灾区。开启透明大页后,内核异步整理大页内存,高峰期引发莫名延迟,内存指标看上去一切正常。

三、线上标准化排查流程

  1. free -h 优先观测 available,确认真实可用内存水位;

  2. vmstat 1 观察 si/so,定位是否存在 Swap 交换;

  3. 查看 /proc/meminfo,重点关注:

    • MemAvailable
    • SwapTotal、SwapFree
    • PageTables、Slab 占用
  4. sar -B 1 观测页面回收、缺页异常指标;

  5. 检查透明大页配置:cat /sys/kernel/mm/transparent_hugepage/enabled

  6. dmesg 检索内核页面回收、内存相关日志,查看有无内核告警。

四、落地优化方案

  1. 观测指标切换基准所有监控告警抛弃 free,以 MemAvailable 作为内存水位判断依据。
  2. 合理调整 swappiness业务服务器推荐设置 10,减少内核主动将内存换入 Swap:

bash

ini 复制代码
sysctl vm.swappiness=10
  1. 数据库、中间件关闭透明大页 THP

bash

typescript 复制代码
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag
  1. 规范应用内存配置Java 程序 Xmx 不要设置接近整机内存,预留系统与缓存工作内存,避免把可用内存压榨殆尽。

不建议频繁执行 echo 3 > /proc/sys/vm/drop_caches。临时释放缓存治标不治本,频繁操作反而加剧 IO 波动,只能应急,不能常态化使用。

五、可用巡检脚本(生产直接部署)

脚本功能:监控 MemAvailable 水位、Swap 交换指标,异常输出告警信息。

bash

bash 复制代码
#!/bin/bash
WARN_RATIO=20
MEMINFO=$(cat /proc/meminfo)
AVAIL=$(echo "$MEMINFO" | grep MemAvailable | awk '{print $2}')
TOTAL=$(echo "$MEMINFO" | grep MemTotal | awk '{print $2}')
RATIO=$(( $AVAIL * 100 / $TOTAL ))

# 判断可用内存占比
if [ $RATIO -lt $WARN_RATIO ];then
    echo "【内存预警】可用内存占比低于${WARN_RATIO}% ,当前比例:${RATIO}%"
fi

# 检测Swap活动
VMSTAT=$(vmstat 1 1 | tail -n1)
SI=$(echo $VMSTAT | awk '{print $7}')
SO=$(echo $VMSTAT | awk '{print $8}')
if [ $SI -gt 0 ] || [ $SO -gt 0 ];then
    echo "【内存预警】系统正在频繁进行Swap交换!si:$SI so:$SO"
fi

可配合 crontab 定时执行,对接告警平台。

六、标准化 SOP 与 AIOps 预防思路

  1. 故障初次出现:收集 meminfo、vmstat、进程内存快照,临时优化缓解;
  2. 故障复现:纳入优化清单,调整 swappiness、关闭 THP、优化应用内存参数;
  3. 监控层面:除固定阈值告警,新增available 持续缓慢下降趋势告警,提前捕捉内存缓慢消耗隐患;
  4. AIOps 轻量化思路:定时自动采集内存关键指标,长期绘制基线,区分正常波动与异常内存回收行为。

运维总结

很多运维排查有固定惯性:先看 used、free,容易被表象蒙蔽。内存故障看不见摸不着,卡顿、延迟抖动这类隐性问题,远比直接 OOM 更消耗精力。记住核心准则:MemAvailable 才是衡量内存充裕与否的标准。遇到反复出现的隐性卡顿,不要只盯着表面指标,顺着 Swap、页面回收、内存碎片这条线索深挖,才能从根源解决问题。

相关推荐
qetfw2 小时前
CentOS 7 搭建 Sendmail + Dovecot 邮件服务器:SMTP、POP3、IMAP 与 TLS
linux·centos
明日清晨2 小时前
printf(“%p\n“,&((struct A *)NULL)->m_float)的原理
linux·服务器·前端
Android系统攻城狮3 小时前
Linux PipeWire深度解析之pw_context_add_spa_lib调用流程与实战(二十九)
linux·运维·服务器·音频进阶·pipewire音频进阶
Dovis(誓平步青云)3 小时前
《如何在CentOS 7中添加Plex官方软件源:解决文件磁盘难管理难题》
linux·运维·服务器·后端·生成对抗网络·centos
草莓熊Lotso4 小时前
【Linux网络】深入理解Linux IO多路复用:select服务器完善、内核原理与poll实战
linux·运维·服务器·c语言·网络·c++
byte轻骑兵4 小时前
BlueZ源码编译环境配置全指南:Linux桌面原生编译 + 嵌入式ARM交叉编译 + 定制裁剪与调试实战
linux·arm开发·蓝牙·bluez·电脑蓝牙
纪伊路上盛名在4 小时前
NVML ERROR_ RM has detected an NVML_RM version mismatch
linux·数据库·gpu·驱动
醉逍遥_祥4 小时前
Linux进程与NuttX任务(Linux Processes vs NuttX Tasks)
linux·单片机·嵌入式软件
AndyHeee4 小时前
Linux 内核底层机制:设备树(Device Tree)的数据结构与内存组织
linux·前端·数据结构