数组在*物理*内存中是连续的吗?

Are Arrays Contiguous in *Physical* Memory?

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

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

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


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

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

如果答案取决于编程语言,我对 C 和 C++ 感兴趣,如果它取决于 OS,我对 linux 感兴趣,它的变体如下ubuntu

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

根据定义,page is contiguous. But the physical pages can be mapped in any order. This allows the OS to allocate and deallocate any amount of virtual memory, as long as physical pages (or swap space) are available. Fragmentation at page level isn't an issue for the CPU or cache, but can affect allocation performance, and so Linux page allocation algorithms are constantly evolving, as described in this article.

内的内存

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

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

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

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

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

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

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

I know that array elements are contiguous in virtual memory for sure, but are they in terms of physical memory

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

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

不太可能需要为此担心。

If not, at-least if one element was found in a page then can I suppose the whole page is filled of array elements (in other words they may not be contiguous as one in different pages but contiguous in each single page thus improving performance when reading 1 element we read a full page of nearby element ie 4096 byte instead of reading another page for next elements)?

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

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

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

另请参阅:https://igoro.com/archive/gallery-of-processor-cache-effects/