3

我在 linux 上读过,程序内存布局可以大致如下可视化(我假设它在大多数其他操作系统上是相似的):

内存布局

现在,我不确定我是否记错了,但我认为 CPU 一次就可以将相当大的相邻 RAM 地址块读取到它们最大的缓存级别中。如果是这样,从性能的角度来看,将程序的所有数据保持在尽可能短的内存范围内以防止缓存未命中是有意义的。

但是,如果是这种情况,最好将事情颠倒过来,将向上增长的部分(文本、全局数据和堆)放在向下增长的部分(cl args、env vars 和 stack)之上。但我想真相比那更复杂一点?如果数据段位于与堆栈完全不同的内存部分,这有什么关系吗?

4

2 回答 2

3

翻转事物并将向上增长的部分(文本、全局数据和堆)放在顶部似乎更好?

不会。缓存行通常只有 32 字节到 256 字节。很少有程序使用少于几兆字节的数据,因此共享基本上是无关紧要的。(即使您不使用它,标准库也会为您做很多事情。)

相关的是确保一起使用的数据在内存中保持紧密(并且在某些情况下,与高速缓存行对齐。)

在脚本语言中,数组的每个元素都可能位于它自己的缓存行上。但是在 C 中,您可以将事物紧密结合在一起(使用数组或结构)。在数字操作方面,用 C 重写可以轻松快 100 倍。(或者像 NumPy 这样的高效库)

大多数处理器也有单独的指令和数据缓存。

如果数据段位于与堆栈完全不同的内存部分,这有什么关系吗?

同样,如果您的堆栈可能超过几百字节深(它将是!),那么它甚至不相关。事实上,您的堆栈可能会在一个重要的程序中使用许多缓存行。

如果您想了解更多信息,我建议您尝试阅读Ulrich Drepper 的每个程序员都应该了解的关于内存的知识。这是一本好书,但即使你略读它,你也可以获得一些简洁的信息。(就像通过切换循环索引使程序运行速度提高 20 倍,或者 RAM 不再比硬盘驱动器“随机访问”。)

于 2013-05-17T00:27:36.253 回答
2

程序和缓存之间的距离不一定是问题。缓存使用地址的某些部分来确定它在缓存中的位置和位置。

还要了解,在操作系统、Linux、Windows 等上运行时,您可能纯粹是在虚拟内存地址上运行,因此内存分离只是一种错觉。与另一个小块相邻的一小块程序在物理地址空间中可能相距很远,也可能不是。

然后是缓存在哪里的问题,是在mmu的虚拟端还是物理端。

所以简短的回答是你的缓存和程序和堆可能会或可能不会相互冲突,并且可以做一些简单的事情(如果你可以控制缓存使用的地址空间)来制作缓存对你更好或更坏。例如,您可以在均匀的边界上“条带化”您的数据,从而导致一小部分缓存发生冲突,从而导致过多的读取(假设您没有使用所有缓存行)和驱逐。程序也是如此,频繁使用的函数可能恰好被隔开以导致更多的缓存冲突,或者被隔开以减少彼此之间的冲突。降低或提高你的整体表现。

如果您可以控制系统(并且知道缓存使用哪些地址位),那么编写一个程序来演示这些问题并不难,通过简单地移动基地址来提高或降低相同代码的性能。数据和/或程序功能生效,但不会以其他方式更改程序或数据。缓存内存和它后面的内存之间的增量越大,就越容易看到。

于 2013-05-17T00:42:30.760 回答