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

6 c c++ memory arrays memory-management

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

#define N 100*1024*1024
int arr[N];
Run Code Online (Sandbox Code Playgroud)

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


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

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

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

Nat*_*dge 1

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

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

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

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

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

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