2

我有一个有 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 中?

4

2 回答 2

8

你的问题在这里得到解答。我只想添加一些评论。

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

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

  • 您显式锁定内存区域:可以使用mlock(2)系统调用来告诉操作系统不要从进程虚拟地址空间交换特定范围;
  • 您的系统没有活动的交换区域:这完全阻止了操作系统将页面移出和移回主内存。
于 2013-11-12T16:56:57.657 回答
2

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

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

于 2013-11-06T13:51:59.243 回答