能否查询当前线程所属的NUMA系统内存存储体?
NUMA节点信息获取方案(JVM + C/C++)
JVM 基于 OSHI 的实现
OSHI可先获取系统NUMA拓扑,但没有直接提供线程绑定NUMA节点的API,需结合JNI或底层系统调用实现:
步骤1:枚举系统NUMA节点拓扑
先通过OSHI获取全系统NUMA节点布局,了解每个节点关联的CPU和内存:import oshi.hardware.HardwareAbstractionLayer; import oshi.SystemInfo; import oshi.hardware.NumaNode; public class NumaInfo { public static void main(String[] args) { SystemInfo si = new SystemInfo(); HardwareAbstractionLayer hal = si.getHardware(); for (NumaNode node : hal.getNumaNodes()) { System.out.printf("NUMA节点%d: 内存大小%.2fGB, 关联CPU核心:%s%n", node.getNodeNumber(), node.getMemory() / (1024.0 * 1024.0 * 1024.0), node.getProcessorIds()); } } }步骤2:获取当前线程绑定的NUMA节点
通过JNI调用C代码实现底层查询,示例如下:
C代码片段(编译为动态链接库):#include <jni.h> #include <numa.h> #include <pthread.h> JNIEXPORT jint JNICALL Java_com_example_NumaInfo_getCurrentThreadNumaNode(JNIEnv *env, jobject obj) { cpu_set_t cpuset; CPU_ZERO(&cpuset); pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); for (int i = 0; i < CPU_SETSIZE; i++) { if (CPU_ISSET(i, &cpuset)) { int node = numa_node_of_cpu(i); if (node >= 0) { return node; } } } return -1; }Java端调用代码:
public class NumaInfo { static { System.loadLibrary("numahelper"); } private native int getCurrentThreadNumaNode(); public static void main(String[] args) { NumaInfo info = new NumaInfo(); int node = info.getCurrentThreadNumaNode(); if (node >= 0) { System.out.printf("当前线程所属NUMA节点: %d%n", node); } else { System.out.println("系统不支持NUMA或无法获取节点信息"); } } }
C/C++ 实现方案
Linux 平台(依赖libnuma)
直接调用libnuma接口获取线程亲和CPU对应的NUMA节点:
#include <numa.h> #include <pthread.h> #include <iostream> int getCurrentThreadNumaNode() { cpu_set_t cpuset; CPU_ZERO(&cpuset); pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); for (int cpu = 0; cpu < CPU_SETSIZE; ++cpu) { if (CPU_ISSET(cpu, &cpuset)) { int node = numa_node_of_cpu(cpu); if (node != -1) { return node; } } } return -1; } int main() { if (!numa_available()) { std::cerr << "系统不支持NUMA" << std::endl; return 1; } int node = getCurrentThreadNumaNode(); if (node >= 0) { std::cout << "当前线程所属NUMA节点: " << node << std::endl; } else { std::cout << "无法获取当前线程的NUMA节点" << std::endl; } return 0; }
编译命令:g++ numa_test.cpp -o numa_test -lnuma
Windows 平台
通过Windows API获取线程亲和CPU,再映射到NUMA节点:
#include <windows.h> #include <iostream> int getCurrentThreadNumaNode() { HANDLE hThread = GetCurrentThread(); GROUP_AFFINITY groupAffinity; if (!GetThreadGroupAffinity(hThread, &groupAffinity)) { return -1; } USHORT cpuMask = groupAffinity.Mask; int targetCpu = 0; while ((cpuMask >>= 1) != 0) { targetCpu++; } ULONG nodeNumber; if (GetNumaProcessorNode(targetCpu, &nodeNumber)) { return static_cast<int>(nodeNumber); } return -1; } int main() { int node = getCurrentThreadNumaNode(); if (node >= 0) { std::cout << "当前线程所属NUMA节点: " << node << std::endl; } else { std::cout << "无法获取当前线程的NUMA节点或系统不支持NUMA" << std::endl; } return 0; }
注意事项
- 所有方法仅在支持NUMA的硬件上有效,否则返回-1或提示不支持。
- JVM线程池中的线程可能被复用,需在任务执行时重新获取NUMA节点。
- Linux下需确保libnuma库已安装,Windows需使用Windows 10/Server 2016及以上版本。
内容的提问来源于stack exchange,提问作者Dave11ar
相关产品推荐
相关产品推荐

