在VPS上排查内存时,最常见的场景是:面板显示占用已经接近上限,free里的used却只有一半,进程逐个相加又远超系统总量。看起来像统计错误,实际是进程RSS、内核缓存、Slab以及虚拟机Balloon回收分别记录了不同层次的数据。
如果你正在选机器,或者想先把线路和配置跑通再谈长期方案,可以先看看这几家的线路说明和技术参数:h4y(海外服务器),先看清带宽线路、流量策略和退款条款,再决定要不要迁。
如果还需要把多台节点的内存指标集中整理,ServLlama这类监控工具可用来保存采样结果;它只能帮助观察趋势,不能替代对cgroup和宿主机状态的核验。
RSS是进程当前驻留在物理内存中的页面,包含匿名页和部分文件映射;它不是进程申请的全部虚拟内存,也不等于系统全部缓存。文件读取产生的页缓存可以在压力下回收,free较低时通常仍能释放,因此available比free更能反映可分配内存。Slab则保存内核对象、目录项等元数据,部分Slab可回收,部分会长期驻留。

在虚拟机中,宿主机可能通过Balloon驱动机制膨胀气球,迫使客户机归还页缓存。气球膨胀并不等于客户机进程RSS全部消失,也不代表客户机已经触发OOM。若宿主机把多个客户机的可见内存都按各自上限出售,而物理内存不足,就会出现名义内存充足、实际回收激烈的内存超卖。
第一,在客户机内查看cgroup内存限额、当前用量及memory.stat,确认当前值是否贴近max;第二,对照宿主机MemAvailable、物理内存总量和所有客户机上限之和,判断是否长期依赖超卖。第三,检查Balloon当前大小、回收量和回收失败日志,区分宿主机主动回收与客户机自身缓存不足。

第四,查看cgroup的memory.events和PSI:出现oom、oom_kill或持续发生高内存压力,才是已经触发或逼近OOM触发判定的依据;单纯的free偏低、缓存很大,并不能直接判定风险。若无法进入宿主机,至少应同时保存客户机RSS、available、cgroup事件和Balloon状态;只截一张free输出,很容易把缓存回收误判为泄漏,或把真正的限额压力忽略掉。
容器触碰cgroup 内存限额时,内核通常先回收页缓存,而非立即终止进程。干净文件页可丢弃,脏页须先写回;缓存充足的业务即使显示高占用,也能继续运行。匿名页、私有堆和不可回收的内核内存较多时,进程才更容易被杀。
“内存超卖”须分层判断:各 cgroup 上限之和大于物理内存,只表示配额隔离,不等于宿主机已经超卖。应结合 Committed_AS、CommitLimit、MemAvailable 和回收压力确认。容器 RSS 还可能重复计算共享页,观察真实工作集应优先看 PSS。
还要注意,cgroup v1 的 usage 通常包含缓存,v2 的 memory.current 也并非纯 RSS;应结合 anon、file、kernel、slab 等字段拆分,不能把总量直接等同于业务占用。

Balloon 驱动不是把宿主机内存塞入客户机,而是宿主机通过 virtio 设定回收目标,客户机驱动促使内核交回可回收页面。部分实现会先膨胀客户机页面,这些页面可能计入驱动所在的 cgroup,使 memory.current 上升而业务 RSS 不变;两侧的 balloon 容量与客户机可用内存也不是同一口径。
判定 OOM 触发不能只看 free。cgroup v2 应检查 memory.events 的 oom、oom_kill 增量,并对照 memory.current、memory.max、memory.stat;v1 则看 memory.failcnt、memory.oom_control、usage_in_bytes。即使宿主机有空闲,只要 cgroup 无法在限额内回收并完成分配,也会触发 cgroup OOM;它与全局 OOM、swap 抖动不同。
可执行检查清单:①客户机读取 /sys/fs/cgroup/ 下的 memory.current、memory.max、memory.events、memory.stat;v1 环境读取 limit、usage、failcnt 对应文件。②宿主机核对 /proc/meminfo 中的 MemAvailable、Committed_AS、CommitLimit。③用 virsh dommemstat 与客户机 /proc/virtio_balloon 对齐 balloon 数值及时间。④检查内核 OOM 日志,确认 oom_kill 是否增长。⑤低峰和高峰各采样一次,再调整缓存、swap 或限额复测,区分业务增长、缓存回收、balloon 回收与 OOM。