numastat —— 按 NUMA 节点看内存分配命中/未命中
这个工具是做什么的
numastat 是排查 NUMA 内存问题的关键:它告诉你内存分配有多少落在了本地节点(命中)、多少被迫去了远程节点(未命中),以及某个进程的内存具体分布在哪些节点。属 numactl 包。原理见 numa。
可以回答什么问题
| 问题 | 怎么用 |
|---|---|
| 整机远程内存访问多不多? | numastat 看 numa_miss / other_node 占比 |
| 远程访问是持续发生还是历史累计? | watch -d -n 1 numastat 看增量变化 |
| 某个进程的内存在哪个节点?分布均匀吗? | numastat -p <PID> 看各节点分布 |
| 进程内是哪段内存在远程节点? | cat /proc/<PID>/numa_maps 看每段内存的 N0=... N1=... |
数据来源
- 整机统计:读每个节点的
/sys/devices/system/node/node<N>/numastat(内核维护的 per-node 分配计数:numa_hit/numa_miss/…)。 - 按进程(
-p):读/proc/<pid>/numa_maps,把该进程各内存段落在哪个节点汇总成表。 - 由此决定的特性:整机计数是开机以来的累计值,要判断"现在"的趋势得隔一段时间看两次做差(或看增长速度),单看一次只是历史总量。
一、整机节点统计
numastat node0 node1
numa_hit 1203847113 998172340
numa_miss 402118 15872044
numa_foreign 15872044 402118
interleave_hit 18324 18201
local_node 1203201847 997903122
other_node 645266 269218核心字段(判断远程访问多不多):
| 字段 | 含义 | 判读 |
|---|---|---|
numa_hit | 想在本节点分配、且成功的次数 | 越高越好(本地访问) |
numa_miss | 想在本节点分配、但本地不够被迫分到别处 | 持续增长 = 本地内存不足,产生远程访问 |
numa_foreign | 本想分到别的节点、结果落到了本节点 | 与别人的 miss 对应(A 的 miss 常是 B 的 foreign) |
local_node | 进程在本节点运行且内存也在本节点 | 越高越好 |
other_node | 进程在本节点运行但内存在别的节点 | 高 = 远程访问多,是要优化的信号 |
interleave_hit | interleave 策略成功分配数 | 用了 --interleave 才有意义 |
判断法:
numa_miss/other_node相对numa_hit/local_node占比高,或两次采样间它们增长快,说明有大量远程内存访问,该考虑绑定(numactl)或调整内存分配方式。
二、按进程看内存分布(最实用,-p)
numastat -p <PID> # 或 numastat -p 进程名Per-node process memory usage (in MBs) for PID 4043 (myapp)
Node 0 Node 1 Total
Huge 0.00 0.00 0.00
Heap 512.30 18.44 530.74
Stack 0.13 0.00 0.13
Private 820.11 402.55 1222.66
----------------- --------------- --------------- ---------------
Total 1332.54 420.99 1753.53一眼看出该进程的内存在两个节点的分布。如果进程主要跑在 Node0,却有几百 MB 落在 Node1(如上例 Private 有 402MB 在 Node1)→ 这部分是远程访问,是优化目标。理想情况是内存集中在它运行的那个节点。
三、按内存类型汇总(-m、-c)
numastat -m # 各节点的 meminfo 式明细(MemFree/FilePages/AnonPages...)
numastat -c # 紧凑输出,节点多时好看
numastat -z # 隐藏全 0 的行,聚焦有数据的四、看"现在"而非"累计":两次做差
整机 numastat 是累计值,想看当前速率:
watch -d -n 1 numastat # 每秒刷新,-d 高亮变化的数字,直接看哪列在涨
# 或手动隔几秒跑两次,对比 numa_miss/other_node 的增量numa_miss、other_node 在负载期间快速增长 = 此刻正在大量远程分配,比看累计绝对值更能定位实时问题。
五、关键指标速查
| 指标 | 缩写/英文 | 正常值 | 异常信号 |
|---|---|---|---|
| 本地命中 | numa_hit / NUMA Hit | 越高越好 | — |
| 本地未命中 | numa_miss / NUMA Miss | 接近 0 | 持续增长 → 本地内存不足 |
| 外来分配 | numa_foreign / NUMA Foreign | 与别的节点 miss 对应 | — |
| 本地运行+本地内存 | local_node / Local Node | 越高越好 | — |
| 本地运行+远程内存 | other_node / Other Node | 0 或极少 | 占比高 → 需要 NUMA 优化的关键信号 |
| interleave 命中 | interleave_hit | 用了 interleave 才关注 | — |
| 进程各自节点分布 | Per-process Node Distribution | 集中在运行节点 | 大量内存在其他节点 → 远程访问 |
六、常见排查方法与分析
6.1 判断整机是否有远程访问问题
# 两步做差看趋势
numastat → 记录 other_node 的基数
# 跑一段负载后
numastat → 对比 other_node 增量
→ other_node 增长快 → 存在远程访问
→ numastat -p <PID> → 逐个进程看谁的内存跨节点6.2 定位哪个进程在跨节点
numastat -p <PID> → 看各节点分布
→ 进程跑在 node0 但内存 40% 在 node1 → 大量远程访问
→ cat /proc/<PID>/numa_maps | grep N1= | head
→ 找出落在 node1 的具体内存段
→ 该段是堆还是 mmap? 是否需要在 node0 重新分配6.3 实时监控远程访问速率
watch -d -n 1 numastat # -d 高亮变化,盯住 other_node 列
# other_node 负载期间快速增长 → 此刻正在大量远程分配6.4 确认绑定是否生效
# 绑前
numastat → other_node 有值
# 绑后(numactl --cpunodebind=0 --membind=0)
numastat -p <PID> → 所有内存都在 Node 0
# 其他节点列全为 0 → 绑定生效七、交叉引用
numastat -p 说"有多少在远程节点",要落到"是哪块内存":
cat /proc/<PID>/numa_maps # 每个映射段:地址 + 策略 + 各 node 上的页数(N0=.. N1=..)例如某行 ... N0=12000 N1=45000 表示这段内存大部分页在 node1——若进程跑在 node0,就是它。
六、结合本仓库
numactl -H # 先确认是 NUMA 机器
./cpu_demo & # 选个场景跑起来
numastat -p $(pgrep cpu_demo) # 看它内存落在哪个节点(小程序基本集中在一个节点)
numastat # 看整机 numa_hit/miss⚠️ 单节点机器上
numastat只有一列 node0、miss 恒为 0——没有远程访问可言。这些指标只在多路 NUMA 机器上才有分析价值。
总结
numastat 是验证 NUMA 本地化效果的工具:整机看 per-node 的 numa_hit/miss、local/other_node 计数(均为开机累计值,需两次做差看趋势),-p 看具体进程各段内存在节点间的分布;判断准则是进程应“在哪节点跑、内存就在哪节点”,other_node 持续增长或进程大量内存落在异节点,就是需要绑定的信号。