进程ps/top RSS远低于cgroup memory.stat的原因及THP机制问询
问题背景
我们有一个运行在K8s Pod中的Go 1.19版本程序,节点上ps/top工具显示的进程RSS值远低于cgroup memory.stat中的RSS值。
cgroup memory.stat 内容
$ cat memory.stat cache 547885056 rss 7860129792 <-- cgroup中的rss远高于"ps -aux"的值 rss_huge 5066719232 <-- 注意这里rss_huge数值也很高 shmem 0 mapped_file 0 dirty 20480 writeback 0 swap 0 pgpgin 450943252 pgpgout 450125090 pgfault 1097413913 pgmajfault 0 inactive_anon 0 active_anon 7859318784 inactive_file 546922496 active_file 962560 unevictable 0 hierarchical_memory_limit 12884901888 hierarchical_memsw_limit 12884901888 total_cache 547885056 total_rss 7860129792 total_rss_huge 5066719232 total_shmem 0 total_mapped_file 0 total_dirty 20480 total_writeback 0 total_swap 0 total_pgpgin 450943252 total_pgpgout 450125090 total_pgfault 1097413913 total_pgmajfault 0 total_inactive_anon 0 total_active_anon 7859318784 total_inactive_file 546922496 total_active_file 962560 total_unevictable 0
docker stats 输出
$ docker stats c39bc01d525e CONTAINER ID CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS c39bc01d525e 49.27% 7.88GiB / 12GiB 65.67% 0B / 0B 0B / 24.6kB 106
进程RSS统计
该cgroup管理3个进程,主进程PID为496687,其RSS仅为5205340,远低于cgroup和docker stats的数值:
$ cat cgroup.procs 496644 496687 496688 $ ps -aux | grep -E "496644|496687|496688" USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 496644 0.0 0.0 1604 1464 ? Ss Oct28 0:00 sh ./bin/start.sh root 496687 26.5 0.4 6466348 5205340 ? Sl Oct28 7271:55 /go/release/bin/golang-app root 496688 0.0 0.0 1588 608 ? S Oct28 0:31 tail -f /dev/null
smaps 统计细节
通过smaps统计主进程的内存指标,总和与ps显示接近,但仍远低于cgroup数值:
# Rss总和 $ cat /proc/496687/smaps | grep Rss | awk -F':' '{print $2 }' | awk 'BEGIN {sum=0} {sum+=$1} END {print sum}' 4645704 # AnonHugePages总和 $ cat /proc/496687/smaps | grep AnonHugePages | awk -F':' '{print $2 }' | awk 'BEGIN {sum=0} {sum+=$1} END {print sum}' 524288 # Size总和 $ cat /proc/496687/smaps | grep -E "^Size:" | awk -F':' '{print $2 }' | awk 'BEGIN {sum=0} {sum+=$1} END {print sum}' 6466352
THP配置
$ cat /sys/kernel/mm/transparent_hugepage/enabled [always] madvise never $ cat /sys/kernel/mm/transparent_hugepage/defrag always defer defer+madvise [madvise] never $ cat /sys/kernel/mm/transparent_hugepage/shmem_enabled always within_size advise [never] deny force
系统信息
已关闭swap,无swap缓存:
$ uname -a Linux 4.14.15-1.el7.elrepo.x86_64 #1 SMP Tue Jan 23 20:28:26 EST 2018 x86_64 x86_64 x86_64 GNU/Linux $ cat /etc/redhat-release Red Hat Enterprise Linux Server release 7.9 (Maipo)
问题与解答
1. 导致ps/top显示的RSS远低于cgroup memory.stat中RSS的原因是什么?
核心原因是透明大页(THP)的统计方式差异:
- cgroup的
rss统计的是实际分配给该cgroup的物理内存总量,包含所有已分配的内存页,包括THP的完整大小(默认2MB/页),即使THP中只有部分内存被进程实际使用。 - 而
ps/top的RSS统计的是进程实际映射并主动使用的内存页,对于THP,只会统计其中被进程实际写入/访问的部分,未被使用的THP空间不会被计入进程RSS,但会被cgroup统计为已分配的内存。
结合你的数据,cgroup中rss_huge高达5GB左右,这部分就是未被进程完全使用但已被分配的THP空间,是两者数值差异的主要来源。
2. 根据kernel文档,cgroup memory.stat中的rss包含transparent hugepages,THP是否也会被计入ps/top显示的RSS?
THP会被计入ps/top的RSS,但统计逻辑不同:
- cgroup的
rss直接按THP的完整页大小统计,只要THP被分配给cgroup下的进程,不管是否被完全使用,都会全额计入。 ps/top的RSS只统计THP中被进程实际访问、写入的部分,未被使用的THP内存不会被统计到进程的RSS中。
这就导致同样的THP资源,在cgroup和ps/top中的统计值出现巨大差距。
3. 若差异由THP导致,其影响内存统计的机制是什么?
THP影响内存统计的核心机制在于内存页的分配与使用统计逻辑差异:
- THP分配逻辑:当THP开启(你的配置是
always),内核会优先为进程分配2MB的大页,而非常规4KB小页。即使进程只需要少量内存,内核也可能提前分配完整的THP。 - cgroup统计逻辑:cgroup的内存统计以“已分配给该cgroup的物理内存”为基准,只要THP被分配给cgroup下的进程,不管是否被使用,都会按完整2MB大小计入
rss和rss_huge。 - ps/top统计逻辑:
ps/top读取的是/proc/[pid]/stat中的RSS值,该值统计的是进程实际“驻留”在物理内存中且被主动使用的页面,对于THP,只有其中被进程实际访问过的部分会被计数,未被使用的空间不会被统计。
简单来说,cgroup统计的是“已分配给容器的内存”,而ps/top统计的是“进程实际在使用的内存”,THP的预分配特性放大了两者的统计差异。
内容的提问来源于stack exchange,提问作者jim
相关产品推荐
相关产品推荐

