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