如何解决数组在*物理*内存中是连续的吗?
我知道数组元素在虚拟内存中肯定是连续的,但它们在物理内存方面是否像这样?
#define N 100*1024*1024
int arr[N];
请注意,到目前为止,你们中的大多数人都说答案是否定的,但我的主要问题还是下面以粗体显示的问题。
如果没有,至少如果在页面中找到一个元素,那么我可以假设整个页面都填充了数组元素(换句话说,它们在不同页面中可能不连续但在每个单页中是连续的,因此在读取 1 个元素时提高了性能,我们读取了附近元素的整页,即 4096 字节,而不是为下一个元素读取另一页)?
如果是,如果我尝试分配一个没有可用连续物理内存的大数组怎么办(我相信这种情况经常发生)?
如果答案取决于我对 C 和 C++ 感兴趣的编程语言,如果它取决于我对 linux 感兴趣的操作系统及其变体,例如 ubuntu
解决方法
在 Linux x86 上,连续的虚拟内存以 4 KB 的页面分配:
根据定义,page 中的内存是连续的。但是物理页面可以按任何顺序映射。只要物理页面(或交换空间)可用,操作系统就可以分配和释放任何数量的虚拟内存。页面级别的碎片不是 CPU 或缓存的问题,但会影响分配性能,因此 Linux 页面分配算法不断发展,如 this article 中所述。
这意味着一个大的连续数组将以 4 KB 的块(对齐到 4 KB)驻留在 RAM 中。第一个和最后一个块可能会占据页面的一部分,其余的将占据整个页面。
,虚拟内存的每一页都同样映射到物理内存的一页;对于小于页面的单位没有重新映射。这是分页原理所固有的。假设 4KB 页,在页表中查找 32 或 64 位地址的前 20 或 52 位以标识物理页,低 12 位用作该物理页的偏移量。因此,如果您在虚拟内存的同一页中有两个地址(即虚拟地址仅在其低 12 位上有所不同),那么它们将位于物理内存的某个单页中的相同相对偏移量处。 (假设虚拟页面完全由物理内存支持;它当然可以随时换出。)
对于不同的虚拟页面,根本无法保证它们是如何映射到物理内存的。它们可以很容易地映射到物理内存的完全不同的位置(当然也可以换出一个或两个)。
因此,如果您在虚拟内存中分配了一个非常大的数组,则不需要足够大的连续物理内存块可用;操作系统可以简单地将这些虚拟内存页面映射到物理内存中的任意页面。 (或者更有可能的是,它最初会保留未映射的页面,然后在您触摸页面并触发页面错误时以较小的块为它们分配物理内存。)
这适用于进程虚拟内存的所有部分:静态代码和数据、堆栈、使用 malloc/sbrk/mmap
动态分配的内存等
Linux 确实支持 huge pages,在这种情况下,同样的逻辑适用,但页面更大(几 MB 或 GB;可用大小由硬件固定)。
除了硬件 DMA 等非常专业的应用程序之外,应用程序程序员通常没有任何理由关心物理内存在幕后的排列方式。
,我知道数组元素在虚拟内存中肯定是连续的,但它们在物理内存方面是连续的
没有。你和我每天使用的所有计算机都有一个 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/
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。