首页/系统/Linux 内核与性能调优速查/cgroup v2 memory.stat 构成分析
内存与 OOM58 条

cgroup v2 memory.stat 构成分析

memory.stat 拆分内存构成:anon、file、slab、shmem 及 pgscan/pgsteal、pgmajfault 等,用于区分泄漏(anon 涨)与缓存(file 涨)。

文件是什么

cgroup v2 的 memory.stat 把该组的内存用量拆成构成明细:anon(匿名页,通常是堆与栈)、file(文件页缓存)、slab(内核对象,分可回收与不可回收)、shmem(tmpfs 等共享内存),另有 pgscan、pgsteal、pgmajfault、workingset_refault 等回收与缺页计数。它的核心价值是回答「这些内存到底是谁在用」:anon 持续增长指向泄漏或缓存膨胀,file 增长通常只是页缓存,压力下可被回收。

基本信息

接口路径/sys/fs/cgroup/<组>/memory.stat
占用类字段anon、file、slab、slab_reclaimable、slab_unreclaimable、shmem
计数类字段pgscan、pgsteal、pgmajfault、workingset_refault(累计值)
混存提示同类文件里既有即时值也有累计值,读法不同
配套接口memory.current / memory.peak / memory.events
cgroup 版本v2 字段集;v1 的 memory.stat 字段名与含义有差异

典型使用场景

  • 判断容器内存增长是泄漏还是缓存膨胀:看 anon 与 file 的结构变化方向
  • 排查热页反复被回收:workingset_refault 偏高说明活跃工作集装不下,限额过紧
  • 核对 tmpfs 占用:shmem 单独列出,常被误当成可回收缓存
  • 定位内核对象增长:slab_unreclaimable 持续上涨需排查内核或驱动对象
  • 为限额调整提供量化依据,而不是只看 memory.current 一个数字

查看与对比

查看与对比
grep -E '^(anon|file|slab|shmem|pgmajfault|workingset) ' /sys/fs/cgroup/myapp.slice/memory.stat  # 关键字段
awk '/^(anon|file|slab|shmem) /{s+=$2; print} END{print "sum(KiB)=", s}' /sys/fs/cgroup/myapp.slice/memory.stat  # 主要构成汇总
grep -E 'workingset_refault|pgscan' /sys/fs/cgroup/myapp.slice/memory.stat  # 回收压力信号
cat /sys/fs/cgroup/myapp.slice/memory.current  # 与各项之和对照,确认口径
grep -E 'Slab|SUnreclaim' /proc/meminfo  # 宿主侧 slab 总量做参照
sleep 60  # 隔一分钟再采一次,比较增量比单次读取更有意义

字段读法

字段含义判读要点
anon匿名页(堆、栈等应用数据)持续增长指向泄漏或缓存膨胀
file文件页缓存可回收,压力下会自动释放
slab内核对象占用需区分可回收与不可回收部分
shmemtmpfs 等共享内存计入内存且不易回收,常被误判为缓存
workingset_refault热页被回收后又读回的次数偏高说明工作集与限额不匹配
pgmajfault主缺页(需要磁盘 IO)次数增长代表访问路径上有磁盘等待
占用类字段(anon/file/slab/shmem)是即时值,计数类字段(pgmajfault、pgscan、workingset_refault)是累计值,两者混在同一个文件里。对累计值必须两次采样求差,用同一套读法处理会得出结论错误。
容器里的 memory.stat 只统计该组,而 /proc/meminfo 是宿主全局视图。排查时先确定视角:要判断容器自身行为看 cgroup 文件,要判断宿主整体压力看 meminfo 与 zoneinfo。

易错点

  • 把 file 或 shmem 的增长当作泄漏:页缓存可回收,shmem 需单独确认;泄漏的证据是 anon 的持续单调增长
  • 用单次采样读计数字段:pgscan、workingset_refault 都是累计值,求增量才有诊断价值
  • 混淆 memory.stat、memory.events、memory.current 的口径:三者用途不同,交替使用时要说明依据
  • 忽略 slab 的可回收性区分:slab_reclaimable 会在压力下释放,slab_unreclaimable 才是真正的疑点
  • 在 cgroup v1 上按 v2 字段名取值:v1 字段集不同,读到空值或错误值却不自知

数据来源与参考

  • Linux 内核 Documentation/admin-guide/cgroup-v2.rst
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌