上一篇 下一篇 分享链接 返回 返回顶部

美国服务器可用内存不足如何排查:区分缓存、交换和OOM进程占用

发布人:Minchunlin 发布时间:1 天前 阅读量:9
美国服务器可用内存不足如何排查:区分缓存、交换和OOM进程占用

美国服务器出现响应变慢、请求超时或进程突然退出时,监控上的“内存使用率高”只能说明需要进一步检查,不能直接认定是内存泄漏。Linux 会利用空闲内存做文件缓存;另一方面,即使整机看起来还有可用内存,受内存限额约束的服务也可能触发 OOM。排查时先确认异常发生的时间和受影响的服务,再判断是真正的内存压力,还是缓存、交换、限额或进程占用造成的不同现象。

建议按以下顺序检查:先看 MemAvailable 是否持续偏低;再看交换分区是否正在频繁换入、换出;随后查同一时间段的 OOM 记录;最后结合进程内存、缓存构成和服务内存限额定位原因。不要仅凭某一次 free 输出中的 free 数值、已使用的交换空间,或一次进程排名就执行重启。

以下命令适用于有 SSH 访问权限的 Linux 服务器。free、vmstat 和 /proc 查询主要是读取状态;读取内核日志可能需要管理员权限。如果业务运行在容器中,还应区分宿主机的内存状态与容器或服务自身的限额。

先确认:是真正缺内存,还是“空闲内存少”

先在故障发生时或尽可能接近故障的时段,记录系统内存概况:

date
free -h
grep -E '^(MemTotal|MemFree|MemAvailable|Buffers|Cached|SReclaimable|SUnreclaim|Shmem|SwapTotal|SwapFree|AnonPages|Dirty|Writeback):' /proc/meminfo

优先看 MemAvailable,而不是只看 MemFree。MemFree 是当前未使用的内存;MemAvailable 是内核估算在不明显依赖交换的情况下,可供新进程使用的内存。后者考虑了部分可回收缓存,但仍是估算值,不等于所有缓存都能立即、无代价地释放。

根据结果继续分支判断:

  • MemFree 低,但 MemAvailable 尚可,业务也没有持续变慢:可能主要是系统在利用内存做缓存。继续观察趋势,不宜仅为提高空闲数值而清理缓存。
  • MemAvailable 持续下降,同时业务延迟上升或进程分配内存失败:更符合实际内存压力,需要检查交换活动、进程增长和限额。
  • 整机 MemAvailable 尚可,但只有某个服务反复退出:优先查该服务的内存限额及 OOM 记录,不能用整机剩余内存排除局部 OOM。

Cached、SReclaimable 可辅助判断文件缓存和可回收内核缓存的规模,但不能把它们简单相加,当作一定可用的内存。Shmem 可能与共享内存或临时文件系统有关;SUnreclaim 偏高且持续增长时,也不能笼统归为“可回收缓存”。如果缓存数值大,而 MemAvailable 仍很低,就应继续查是谁占用内存,不要在“缓存会自动释放”这一判断上停下。

再看交换:已使用不等于正在发生抖动

交换空间已有占用,只说明部分内存页曾进入交换空间;即使当前压力缓解,它们也未必马上被换回。判断交换是否正在影响业务,要看故障时段是否持续发生换入、换出:

vmstat -w 1 6

该命令每秒输出一次,共输出六次,查询本身不会修改系统状态。重点看后续几行的 si(从交换空间换入)和 so(换出到交换空间);首行通常反映开机以来的平均情况,不适合单独判断当前压力。

如果 si、so 在异常时段持续出现,并伴随响应变慢、MemAvailable 偏低,说明内存压力可能已转化为交换开销,应继续定位占用来源。如果交换已使用,但采样期间 si、so 基本没有活动,就不能把当前卡顿直接归因于“交换空间被占用”。短暂采样也可能错过间歇性问题,必要时应在故障再次出现时复测,并对照同一时段的业务延迟。

不要把关闭交换、强制释放缓存或单纯调整交换倾向作为第一步。这些操作不能解释内存由谁占用;在内存紧张时,贸然关闭交换还可能使进程更快遇到内存分配失败或 OOM。

查 OOM:确定谁被终止,以及在哪里触发

OOM 是内存无法满足分配要求时可能出现的结果,不是进程异常占用的直接证明。先把业务报错时间与内核记录对齐。以下示例查询近两小时日志,实际排查时应按故障时间调整范围:

sudo journalctl -k --since "2 hours ago" --no-pager | grep -Ei 'out of memory|oom|killed process|memory cgroup'

查看记录时,重点区分两件事:一是日志指向整机内存压力,还是某个内存控制组的限额;二是被终止进程的 PID、名称和时间,是否与业务故障吻合。被 OOM 终止的进程不一定是最初造成内存增长的进程,还要结合故障前后的进程占用和服务配置判断。

如果日志提示与 memory cgroup 有关,即使宿主机还有可用内存,也要检查对应服务或容器的限额。如果日志显示整机内存不足,则回到系统范围查进程、共享内存和不可回收占用。没有查到 OOM 记录,也不能直接断定不存在内存问题:日志可能未保留、查询时段不符,或应用是在分配失败后自行退出。此时应同时查看服务日志中的内存分配错误,并确认异常是否发生在上一次启动之前;系统未保留历史内核日志时,重启后的查询可能找不到旧事件。

定位占用:从进程排名查到服务限额

先按常驻内存查看当前进程。下面的 ps 输出中,RSS 通常以 KiB 表示:

ps -eo pid,ppid,user,comm,rss,vsz --sort=-rss | head -n 16

排名靠前并不自动等于异常。应对照进程所属服务、正常业务负载及前后多次采样:如果某个进程的 RSS 持续增长,系统 MemAvailable 同时下降,它才更值得追查。VSZ 表示虚拟地址空间规模,不能直接当作实际占用的物理内存;多个进程的 RSS 也可能重复计入共享页面,不能简单求和与整机使用量比较。

确认目标 PID 后,可进一步查看该进程状态。将示例 PID 替换为实际值,并先核对它仍属于同一个进程:

PID=1234
ps -p "$PID" -o pid,ppid,etime,rss,vsz,comm
grep -E '^(Name|VmRSS|VmSwap|Threads):' "/proc/$PID/status"

如果系统提供 /proc/PID/smaps_rollup,且当前账号有读取权限,还可以针对少量可疑进程查看汇总数据:

PID=1234
grep -E '^(Rss|Pss|Private_Dirty|Swap):' "/proc/$PID/smaps_rollup"

其中 Pss 会按比例分摊共享页面,比直接累加多个进程的 RSS 更适合比较一组进程的实际占用。该文件不存在或无权读取时,不必为完成这一步而改变服务权限;可先用进程趋势、服务日志和监控继续定位。进程已经退出的情况下,当前 ps 排名也无法还原故障瞬间,应以已有历史监控和 OOM 日志为准。

若进程排名解释不了整机内存下降,再回看 /proc/meminfo 中的 AnonPages、Shmem、SUnreclaim 等项目,判断是匿名内存、共享内存,还是不可回收内核占用在增长。这样可以避免把所有未出现在进程榜首的内存都归为“缓存”。

整机有空余,但服务仍 OOM

对由 systemd 管理、且使用 cgroup v2 的服务,可以检查其所属控制组。先确认系统类型,再将示例服务名换成实际名称:

stat -fc %T /sys/fs/cgroup
systemctl show your-service.service -p ControlGroup -p MemoryCurrent -p MemoryMax

当第一条命令输出 cgroup2fs,且服务仍在运行、ControlGroup 路径有效时,可读取对应数据:

SERVICE=your-service.service
CG=$(systemctl show "$SERVICE" -p ControlGroup --value)
if [ -n "$CG" ] && [ -r "/sys/fs/cgroup${CG}/memory.events" ]; then
    cat "/sys/fs/cgroup${CG}/memory.current"
    cat "/sys/fs/cgroup${CG}/memory.max"
    cat "/sys/fs/cgroup${CG}/memory.events"
fi

memory.current 是当前控制组使用量,memory.max 是该层的限额,值为 max 表示该层没有设置此项上限,但仍需留意上级控制组。memory.events 中的 oom、oom_kill 等是事件计数,应比较同一控制组在故障前后的变化,并结合内核日志;单看一个已有计数,无法证明刚刚发生了 OOM。服务停止后控制组可能消失,上述命令没有输出时,应回查日志,而不是把它解释为“没有限额问题”。

如果业务运行在容器中,也要在对应容器及宿主机侧核对内存限额和事件。容器看到的整机指标、宿主机空余内存,与该容器实际可用的额度不是同一个判断对象。

修复后怎样确认问题已经消失

处理方式取决于已确认的分支,而不是统一执行“清缓存”或“重启服务器”:

  • 进程占用持续增长:核对增长是否随请求量、任务数量同步变化;若与负载不符,检查应用日志、近期变更和内存持有路径。需要重启止损时,先确认影响范围和可恢复方式,保留故障时的进程与日志数据;重启只清除了当下占用,不代表根因已消除。
  • 服务限额触发 OOM:先确认限额配置及业务合理峰值,再评估调整限额或降低服务占用。修改前保存原配置,明确受影响服务;若调整后出现新的资源争用,应恢复原配置并按既定服务变更流程回滚。
  • 缓存为主且无持续压力:不必为了降低“已使用内存”而操作。继续观察 MemAvailable、业务延迟和是否出现新的交换活动。
  • 交换活动持续且内存不足:先处理造成压力的进程或服务,再评估资源需求;仅让交换使用量变小,不足以证明业务已经恢复。

验证时应覆盖一次接近故障时的实际业务负载,并对照修复前后的同类指标:MemAvailable 不再持续下滑,vmstat 不再出现与卡顿同步的持续换入、换出,目标进程的内存曲线趋于稳定,相关控制组的 OOM 事件不再增加,服务日志也没有新的内存分配失败。若只是重启后短时间恢复,随后占用又按相同趋势增长,应继续追查原因。

后续监控至少保留可用内存、交换换入换出、关键进程或服务内存、控制组 OOM 事件和业务延迟,并让这些数据能够按时间相互对照。这样下次美国服务器再出现“内存不足”告警时,才能迅速分清是正常缓存、持续内存压力,还是局部限额先被触发。

目录结构
全文