登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  linux

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;因此读取时要先保留字段含义,再做单位换算。

 /proc/meminfo 中 HugeTLB 字段和页面大小的静态关系说明图
图1:结构说明图,展示 /proc/meminfo 的 HugeTLB 字段关系,不是运行截图或现场读数。

按字段读取 HugePages 池状态

先用最小命令把相关字段完整列出。这样可以同时看到池大小、空闲情况、预留情况和页面大小,避免只读 HugePages_Total 后误判。

# 只读取 HugeTLB 相关字段,保留内核给出的原始单位
grep -E '^(HugePages_|Hugepagesize|Hugetlb):' /proc/meminfo

各字段可以按下面的方式理解:

字段含义常用判断
HugePages_TotalHugeTLB 池中的总页数看池规模
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 控制可超额获得的页数上限;内核文档指出两者共同构成池的最大边界。读取这些文件不等于修改配置,修改时才需要额外的权限、容量和业务影响评估。

 /proc/meminfo、sysctl、sysfs 与 NUMA HugeTLB 入口的边界关系说明图
图2:边界说明图,展示运行时统计与 HugeTLB 配置入口的关系,不是配置界面或运行证据。

用一次快照建立排障基线

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;但读取或修改某些系统接口的权限可能受挂载方式、容器隔离和系统策略影响。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>