NUMA:如何检查分配C ++数组的RAM部分?

时间:2013-11-06 13:42:30

标签: c++ multithreading virtual-memory numa

我的服务器有2个CPU和64GB内存,每个CPU 32GB。

我知道每个CPU都有自己的RAM部分,我们称之为RAM1和RAM2。我想让我的程序知道它分配了哪些RAM(RAM1或RAM2)的数据。

我试图检查指针值:

  // put the thread at i-th CPU, using pthread_setaffinity_np
TData *a = new TData[N];
...
cout << "CPU = " << i << " adress = " << a << endl; 

但输出看起来是随机的。我想这是因为地址是虚拟的。虚拟内存地址和部分RAM之间是否存在对应关系?

如何检查我的阵列“a”分配到哪个RAM?

2 个答案:

答案 0 :(得分:4)

您的问题已经回答here。我只想补充一些意见。

请注意,调用new []实际上并不分配物理内存。在现代操作系统上,这只会导致开始匿名内存映射。匿名映射与文件系统中的文件不对应,而是由交换(如果有)支持。最初,整个区域指向内核中包含全零的只读页面。只有当您实际写入新分配的内存时,才会安装新的内存页面,该页面将替换访问地址所在页面范围的零页面。这就是为什么我们说零页面是写入时复制(或CoW)映射到进程的虚拟地址空间的原因。默认策略是尝试在同一NUMA节点上分配新页面,其中访问内存区域的线程在该节点上运行。这被称为“第一次触摸”NUMA政策。如果该NUMA节点上没有足够的内存,则该页面将在具有足够可用内存的其他节点上分配。小分配也可能在更大的区域(称为arena)内部结束,由C库内存分配器malloc()(C ++运算符new []调用malloc()进行管理实际的内存分配)。在这种情况下,即使在写入新分配的内存之前,页面可能已经存在于物理内存中。

Linux有一种讨厌的习惯,即在交换时不保留内存区域的NUMA关联。也就是说,如果页面在NUMA节点0上分配,然后换出然后重新交换,则无法保证该页面不会被放置在NUMA节点1上。这使得问题“我的内存分配在哪里”有点棘手,因为连续换出然后换入可能很容易使你在几分之一秒前从move_pages()获得的结果无效。因此,这个问题在以下两个特殊情况下才有意义:

  • 您明确锁定了内存区域:可以使用mlock(2)系统调用来告诉操作系统不要从进程虚拟地址空间交换特定范围;
  • 您的系统没有活动的交换区域:这可以防止操作系统将页面从主内存移回主内存。

答案 1 :(得分:2)

通过MMU虚拟化内存,因此每个进程都会看到大小等于2 ^ 64的内存空间。在这个过程中,地址是虚拟的,所以它们毫无意义。虚拟地址(由应用程序看到)和进程级别的物理地址(在RAM上)之间没有任何矛盾。

您的应用程序应查询操作系统以了解当前使用的物理地址。