【问题标题】:Are Arrays Contiguous in *Physical* Memory? [duplicate]*物理*内存中的数组是否连续? [复制]
【发布时间】:2021-09-14 14:29:13
【问题描述】:

我知道数组元素在虚拟内存中是连续的,但它们是否像这样的物理内存?

#define N 100*1024*1024
int arr[N];

请注意,到目前为止,你们中的大多数人都说答案是否定的,但我的主要问题还是下面的粗体字。


如果不是,至少如果在页面中找到一个元素,那么我可以假设整个页面都充满了数组元素(换句话说,它们在不同页面中可能不连续但在每个单页中都是连续的,因此在读取 1 个元素时提高了性能,我们读取了附近元素的整页,即 4096 字节,而不是为下一个元素读取另一页)?

如果是,如果我尝试分配一个没有可用连续物理内存的大数组(我相信这种情况经常发生)怎么办?

如果答案取决于我对 C 和 C++ 感兴趣的编程语言,如果它取决于我对 linux 及其变体(如 ubuntu)感兴趣的操作系统

【问题讨论】:

  • 物理内存对虚拟内存系统中的程序是不可见的——作为程序员,您不需要对此进行推理。
  • @daniel 是的。 “页面中所有连续的内容对于虚拟内存和物理内存都是连续的”。这是您获得的唯一保证。
  • 连续内存和非连续内存之间没有性能差异。这就是随机访问的意思。
  • @GSerg 这不是我问的...我问它们是否是连续的物理内存,它们是否会在同一页面中连续... A 是 B 并没有说 B 是 A
  • @GSerg 它不会“物理内存中连续的项目”这不是我要再次要求的。我在问它们是否在虚拟内存中是连续的......

标签: c++ arrays c memory memory-management


【解决方案1】:

我知道数组元素在虚拟内存中是连续的,但它们是在物理内存方面吗

没有。您和我每天使用的所有计算机都具有memory management unit 以将虚拟地址转换为物理地址。地址以称为页面的粒度块进行转换,典型的页面大小为 4 kB。在一个页面内,物理地址将是连续的,但需要许多页面的数组很可能最终会完全碎片化并以任意方式分散在物理内存地址中。

即使物理地址是连续的,“物理”地址映射到 RAM 棒上真正的片上位置的方式也取决于主板。

不太可能需要担心这个。

如果不是,至少如果在页面中找到一个元素,那么我可以假设整个页面都充满了数组元素(换句话说,它们在不同页面中可能不是连续的,但在每个页面中都是连续的在读取 1 个元素时提高性能,我们读取附近元素的整页,即 4096 字节,而不是为下一个元素读取另一页)?

如果页面之前没有驻留在 RAM 中,访问它的任何部分都将执行从操作系统的页面文件等中拉取整个页面到 RAM 的昂贵操作(并且操作系统可能会预取一些后续页面以及)。

这仍然不意味着 RAM 中页面的每个部分都可以以相同的速度被访问,因为您仍然受到 CPU 缓存的影响,并且访问缓存比访问主板上的 RAM 还要快。

例如,典型的 CPU 高速缓存行大小为 64 或 128 字节,而不是小于一页。但是访问缓存行的一部分肯定会将整行拉入缓存。

另见:https://igoro.com/archive/gallery-of-processor-cache-effects/

【讨论】:

  • ״即使物理地址是连续的,“物理”地址映射到 RAM 棒上真正的片上位置的方式也取决于主板。״ 这让我感兴趣。 “物理”不是 RAM 上真正的片上位置吗?我在哪里可以阅读有关此的更多信息?
  • 物理地址是内核(和 CPU)在向内存控制器请求数据时发送给内存控制器的地址。内存控制器如何将这些物理地址映射到特定 RAM 芯片上的实际位置是它与 SIMM 之间的私有实现细节。
  • 有什么链接可以让我了解更多关于这个新的低层的信息吗?谢谢
  • @daniel 实际物理 RAM 使用“banks”、“rows”和“columns”寻址。我对此了解不多,但这应该会给您一些要搜索的词。对 RAM 块的读取和写入在 RAM 棒上的所有芯片之间分配,因此这些芯片可以并行工作,这是另一个级别的物理碎片。
  • @daniel:查看 Ulrich Drepper 的优秀论文,"What Every Programmer Should Know About Memory"
【解决方案2】:

虚拟内存的每一页都映射到物理内存的一页;对于小于一页的单位,没有重新映射。这是分页原理所固有的。假设 4KB 页,32 位或 64 位地址的前 20 位或 52 位在页表中查找以识别物理页,低 12 位用作该物理页的偏移量。因此,如果您在同一虚拟内存页面中有两个地址(即虚拟地址仅在它们的 12 个低位上有所不同),那么它们将位于物理内存的某个单页中的相同相对偏移量。 (假设虚拟页面完全由物理内存支持;它当然可以随时换出。)

对于不同的虚拟页面,根本无法保证它们如何映射到物理内存。它们可以很容易地映射到完全不同的物理内存位置(或者当然可以换出一个或两个位置)。

因此,如果您在虚拟内存中分配一个非常大的数组,则不需要足够大的连续物理内存块可用;操作系统可以简单地将这些虚拟内存页面映射到物理内存中的任意页面。 (或者更有可能的是,它最初会保留未映射的页面,然后在您触摸页面并触发页面错误时以较小的块为它们分配物理内存。)

这适用于进程虚拟内存的所有部分:静态代码和数据、堆栈、使用malloc/sbrk/mmap 动态分配的内存等。

Linux 确实支持huge pages,在这种情况下,同样的逻辑适用,但页面更大(几 MB 或 GB;可用大小由硬件固定)。

除了硬件 DMA 等非常专业的应用程序外,应用程序程序员通常没有任何理由关心幕后物理内存的排列方式。

【讨论】:

  • “因此,如果您在虚拟内存中分配一个非常大的数组,则不需要足够大的连续物理内存块可用”这不会提高性能吗?如果我正在读取数组的值,我只需要找到第一个物理页面,然后检查下一页等等,但如果没有发生,那么我需要重新查找下一页,这需要一些时间
  • @daniel:不是这样。由于页面可以任意放置,当您访问下一页时,CPU 必须执行新的页表遍历,以查看该页面在物理内存中的位置并相应地填充 TLB。 (我假设这就是您所说的“重新查找”的意思。)它不能假设它将是下一个连续的物理页面,并且一旦页面遍历完成,它是否成为下一页都没有区别,或者其他地方的页面。
【解决方案3】:

在 Linux x86 上,连续的虚拟内存以 4 KB 的页面分配:

根据定义,page 中的内存是连续的。但是物理页面可以按任何顺序映射。这允许操作系统分配和取消分配任意数量的虚拟内存,只要物理页面(或交换空间)可用。页面级别的碎片对 CPU 或缓存来说不是问题,但会影响分配性能,因此 Linux 页面分配算法在不断发展,如 this article 中所述。

这意味着一个大的连续数组将以 4 KB 的块(与 4 KB 对齐)驻留在 RAM 中。第一个和最后一个块可能占据页面的一部分,其余的将占据整个页面。

【讨论】:

  • 所以除了 2 之外,答案是:“如果不是,至少如果在页面中找到一个元素,那么我可以假设整个页面都充满了数组元素”是正确的吗?
  • @daniel 是的,整个页面将被数组元素填充。
  • @daniel 这个问题没有多大意义。如果在页面中找到数组的至少一个元素,则该数组将在该页面中继续存在,直到该页面或数组结束,以较早者为准。如果数组比页面结束得早,那么页面的其余部分可能被其他东西占用,这意味着您的问题的答案是“否”(因为不是页面的 整个 是专用的到数组),这反过来可能不是您要问的,因为数组在该页面内仍然完全连续(这似乎是您关心的)。
猜你喜欢
  • 2014-03-28
  • 2012-01-08
  • 1970-01-01
  • 2010-10-24
  • 1970-01-01
  • 1970-01-01
  • 2021-11-30
  • 2018-09-10
  • 1970-01-01
相关资源
最近更新 更多