Linux /proc/meminfo 怎样读取 HugePages 使用量
来源:17golang原创
时间:2026-10-27 00:42:19 261浏览 收藏
Linux 上想知道 HugePages 到底配置了多少、还剩多少,最直接的入口是 /proc/meminfo。真正要读的是 HugePages_Total、HugePages_Free、HugePages_Rsvd、HugePages_Surp 和 Hugepagesize;如果只看一个字段,容易把“总池容量”“空闲页”“已预留页”混成同一个数字。
官方参考:https://man7.org/linux/man-pages/man5/proc_meminfo.5.html
最小判断公式是:当前 HugeTLB 池中已从空闲池扣除的页数 =HugePages_Total - HugePages_Free;按单一默认页面大小估算容量时,再乘以Hugepagesize。但如果系统启用了多个 HugeTLB 页面大小,最终总量应以Hugetlb或 sysfs 中各页面大小目录的统计为准。
先分清 HugeTLB 和透明大页
HugePages_Total 这一组字段描述的是 HugeTLB 页面池,通常用于显式预留和分配固定大小的大页。它和透明大页不是一回事:AnonHugePages、ShmemHugePages 等字段描述的是透明大页相关映射,不能拿来替代 HugeTLB 池的总页数。
/proc/meminfo 每行通常由字段名、冒号、数值和可选单位组成。HugePages 计数是页数,Hugepagesize 和 Hugetlb 的单位是 kB;因此读取时要先保留字段含义,再做单位换算。

按字段读取 HugePages 池状态
先用最小命令把相关字段完整列出。这样可以同时看到池大小、空闲情况、预留情况和页面大小,避免只读 HugePages_Total 后误判。
# 只读取 HugeTLB 相关字段,保留内核给出的原始单位 grep -E '^(HugePages_|Hugepagesize|Hugetlb):' /proc/meminfo
各字段可以按下面的方式理解:
| 字段 | 含义 | 常用判断 |
|---|---|---|
HugePages_Total | HugeTLB 池中的总页数 | 看池规模 |
HugePages_Free | 当前还没有被分配的页数 | 看池中余量 |
HugePages_Rsvd | 已经承诺分配、但尚未实际分配的页数 | 看预留压力,不当作已使用量相加 |
HugePages_Surp | 超过 nr_hugepages 持久池目标的超额页数 | 看是否使用了 surplus 页 |
Hugepagesize | 该统计入口对应的默认 HugeTLB 页面大小,单位为 kB | 做单页容量换算 |
Hugetlb | 所有大小 HugeTLB 页面消耗的内存总量,单位为 kB | 多页面大小时看总内存 |
如果某个内核没有启用 HugeTLB 支持,相关字段可能不存在或保持为零。此时不要把“没有字段”直接解释成应用没有使用任何大页,还要结合内核配置和实际使用的分配机制判断。
计算已使用页数和容量
在单一页面大小、只关注当前默认 HugeTLB 池的场景中,可以用 Total - Free 得到已经从空闲池扣除的页数:
# 从 /proc/meminfo 读取数值,并计算池视角的已分配页数
awk '
# 保存 HugeTLB 计数和页面大小,单位先保持为内核原值
$1 == "HugePages_Total:" { total = $2 }
$1 == "HugePages_Free:" { free = $2 }
$1 == "Hugepagesize:" { size_kb = $2 }
END {
# Total - Free 表示已经不在空闲池中的页数
used = total - free
printf "总页数: %d\n空闲页数: %d\n已分配页数: %d\n", total, free, used
printf "单页大小: %d kB\n池总容量估算: %d kB\n池已分配容量估算: %d kB\n", size_kb, total * size_kb, used * size_kb
}
' /proc/meminfo
这里的“已分配容量估算”是池统计口径,不等价于某个进程当前的工作集。HugePages_Rsvd 记录的是已经承诺、但还没有在缺页时真正分配的页;它应该单独观察,不能简单加到 Total - Free 上。
当输出类似 HugePages_Total: 1024、HugePages_Free: 768、Hugepagesize: 2048 kB 时,池视角的已分配页数是 256,单一页面大小下的估算值是 512 MiB。这个计算只说明当前默认池的数量关系,不说明页面属于哪个进程,也不说明所有 HugeTLB 页面都只有这一种大小。
把预留页、超额页单独看待
HugePages_Rsvd 和 HugePages_Surp 解决的是两个不同问题:
HugePages_Rsvd表示应用已经作出分配承诺,但实际页面可能要到缺页时才分配。它更适合判断“未来分配是否已经被预留”。HugePages_Surp表示池中超过/proc/sys/vm/nr_hugepages持久池目标的页。它更适合判断是否发生了超额 HugeTLB 分配。
因此排障时可以先看三组关系:Total 和 Free 说明池的即时余量,Rsvd 说明已承诺但未实际分配的部分,Surp 说明是否越过持久池目标。三者不能用一个“使用率”字段替代。
结合 sysctl 与 sysfs 判断边界
仅靠 /proc/meminfo 可以回答“默认入口看到的池有多少”,但不一定能回答“不同页面大小分别有多少”或“NUMA 节点上怎样分布”。Linux 内核文档把持久池目标、超额上限和多页面大小入口分开描述。
# 读取持久池目标和超额上限;这些是配置边界,不是当前已使用量
for file in /proc/sys/vm/nr_hugepages /proc/sys/vm/nr_overcommit_hugepages; do
# 文件不存在时给出提示,兼容未暴露该接口的内核环境
if [ -r "$file" ]; then
printf '%s: ' "$file"
cat "$file"
else
printf '%s: 不可读取或不存在\n' "$file"
fi
done
# 列出各 HugeTLB 页面大小目录,便于识别多页面大小池
if [ -d /sys/kernel/mm/hugepages ]; then
# 只列目录名,不修改任何配置
find /sys/kernel/mm/hugepages -maxdepth 1 -type d -name 'hugepages-*' -print
else
echo '/sys/kernel/mm/hugepages: 不可用'
fi
nr_hugepages 表示持久 HugeTLB 池目标,nr_overcommit_hugepages 控制可超额获得的页数上限;内核文档指出两者共同构成池的最大边界。读取这些文件不等于修改配置,修改时才需要额外的权限、容量和业务影响评估。

用一次快照建立排障基线
HugePages 数值会随应用分配和释放变化。排查“为什么变少”时,建议保存同一时刻的字段、sysctl 值和页面大小目录,后续再比较两次快照:
# 保存一次只读基线,文件名带时间便于对比不同采样点
stamp=$(date +%Y%m%d-%H%M%S)
out="hugepages-$stamp.txt"
{
# 记录内核提供的 HugeTLB 统计字段
grep -E '^(HugePages_|Hugepagesize|Hugetlb):' /proc/meminfo
# 记录持久池和超额池边界;读取失败不影响前面的统计保存
for file in /proc/sys/vm/nr_hugepages /proc/sys/vm/nr_overcommit_hugepages; do
[ -r "$file" ] && printf '%s: %s\n' "$file" "$(cat "$file")"
done
} > "$out"
# 输出快照文件名,便于交给后续排障记录
printf '已保存: %s\n' "$out"
比较快照时,先看 Total 是否变化,再看 Free、Rsvd 和 Surp 哪个字段变化。若 Hugetlb 与默认页面大小乘积对不上,不要立刻认为统计错误,优先检查 sysfs 是否存在多种 HugeTLB 页面大小。
常见误区与速查表
- 把
AnonHugePages当作HugePages_Total:前者属于透明大页相关统计,后者属于 HugeTLB 池。 - 把
HugePages_Rsvd加到已使用页数里:预留页是承诺状态,应单独展示。 - 只用
Total × Hugepagesize代表全部 HugeTLB 内存:多页面大小时应参考Hugetlb和 sysfs。 - 把
nr_hugepages当成当前已使用量:它是持久池目标,当前使用还要回到/proc/meminfo。
| 想回答的问题 | 优先读取 |
|---|---|
| 默认池总共有多少页 | HugePages_Total |
| 还有多少页没有从池中分配 | HugePages_Free |
| 有多少页已承诺但未实际分配 | HugePages_Rsvd |
| 是否出现超出持久池目标的页 | HugePages_Surp 与 nr_overcommit_hugepages |
| 所有大小的大页消耗多少内存 | Hugetlb 和 /sys/kernel/mm/hugepages |
把字段含义、单位和统计边界分开后,读取 HugePages 使用量就不再是背一个命令:先用 /proc/meminfo 得到池的即时状态,再用 sysctl 和 sysfs 补足持久池、超额页、页面大小与 NUMA 分布信息。
相关问题
HugePages_Free 为 0 就一定是内存泄漏吗?
不一定。它只说明当前入口下没有空闲 HugeTLB 页,还要结合 HugePages_Rsvd、HugePages_Surp、应用分配策略和页面大小判断原因。
为什么 HugePages_Total 乘 Hugepagesize 和 Hugetlb 不一致?
常见原因是系统存在多个 HugeTLB 页面大小。默认页面大小的乘积只对应一个池的估算,Hugetlb 汇总的是所有大小的 HugeTLB 内存。
读取 /proc/meminfo 需要 root 权限吗?
通常只读公开的 /proc/meminfo 不需要 root;但读取或修改某些系统接口的权限可能受挂载方式、容器隔离和系统策略影响。
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
215 收藏
-
219 收藏
-
184 收藏
-
284 收藏
-
478 收藏
-
318 收藏
-
422 收藏
-
392 收藏
-
272 收藏
-
285 收藏
-
252 收藏
-
432 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习