诚然我不明白。假设您有一个存储器,其存储器字的长度为1个字节。为什么不能在未对齐地址(即不能被4整除)的单次存储器访问中访问4字节长的变量,因为对齐地址就是这种情况?
诚然我不明白。假设您有一个存储器,其存储器字的长度为1个字节。为什么不能在未对齐地址(即不能被4整除)的单次存储器访问中访问4字节长的变量,因为对齐地址就是这种情况?
Answers:
现代处理器上的内存子系统仅限于按其字长的粒度和对齐方式来访问内存。这是有多种原因的。
现代处理器具有多个级别的高速缓存,必须将数据拉入高速缓存。支持单字节读取将使内存子系统的吞吐量与执行单元的吞吐量紧密绑定(也称为cpu绑定);这完全使人想起了硬盘驱动器中出于许多相同原因而DMA超越PIO模式的情况。
CPU 始终以其字长读取(32位处理器上为4字节),因此,如果在未对齐的地址访问中(在支持它的处理器上),则该处理器将读取多个字。CPU将读取您请求的地址跨越的每个内存字。这导致访问请求的数据所需的内存事务数量最多增加2倍。
因此,读取两个字节要比读取四个字节慢得多。例如,假设您的内存中有一个结构如下:
struct mystruct {
char c; // one byte
int i; // four bytes
short s; // two bytes
}
在32位处理器上,它很可能按照如下所示对齐:
处理器可以在一个事务中读取这些成员中的每个成员。
假设您有一个结构的压缩版本,也许是从打包网络的地方获取的,以提高传输效率;它可能看起来像这样:
读取第一个字节将是相同的。
当您要求处理器为您提供0x0005的16位数据时,它将不得不从0x0004读取一个字并将其左移1个字节以将其放入16位寄存器中。一些额外的工作,但大多数可以一次完成。
当您从0x0001请求32位时,您将获得2倍的放大倍数。处理器将从0x0000读入结果寄存器并向左移1个字节,然后再次从0x0004读入一个临时寄存器,向右移3个字节,然后OR
与结果寄存器一起移入。
对于任何给定的地址空间,如果体系结构可以假定2个LSB始终为0(例如32位计算机),则它可以访问4倍以上的内存(2个保存的位可以表示4个不同的状态),或者相同数量2位的内存用于标记之类的东西。从地址中减去2个LSB,将使您达到4字节对齐;也称为4字节跨度。每次地址增加时,它实际上是在增加位2,而不是位0,即,最后2位将始终为00
。
这甚至会影响系统的物理设计。如果地址总线需要少2位,则CPU上可以减少2个引脚,电路板上可以减少2条迹线。
CPU可以原子操作对齐的内存字,这意味着没有其他指令可以中断该操作。这对于许多无锁数据结构和其他并发范例的正确操作至关重要。
处理器的存储系统比此处描述的要复杂得多,涉及的也更多。关于x86处理器如何实际寻址内存的讨论会有所帮助(许多处理器的工作方式类似)。
可以从这篇IBM文章中了解到遵守内存对齐的更多好处。
计算机的主要用途是转换数据。现代内存架构和技术经过数十年的优化,以一种高度可靠的方式促进了在更多和更快的执行单元之间进,出,出更多的数据。
我之前提到的另一个性能对齐方式是在(例如在某些CPU上)64B的高速缓存行上对齐。
有关利用缓存可获取多少性能的更多信息,请参阅处理器缓存效果库;从这个关于缓存行大小的问题
对于某些类型的程序优化,了解缓存行可能很重要。例如,数据的对齐可以确定操作是触摸一条还是两条高速缓存行。正如我们在上面的示例中看到的那样,这很容易意味着在未对齐的情况下,操作将慢两倍。
您可以使用某些处理器(nehalem可以做到这一点),但是以前所有内存访问都在64位(或32位)线上对齐,因为总线为64位宽,因此您必须一次获取64位,并且以64位对齐的“块”来获取这些数据要容易得多。
因此,如果您想获得一个字节,则获取64位块,然后屏蔽掉不需要的位。如果字节位于正确的末端,则容易又快速,但是如果该字节位于该64位块的中间,则必须屏蔽掉不需要的位,然后将数据移至正确的位置。更糟糕的是,如果您想要一个2字节的变量,但是将其分成2个块,则需要两倍的所需内存访问。
因此,由于每个人都认为内存便宜,他们只是让编译器根据处理器的块大小对齐数据,从而使代码更快,更高效地运行,但浪费了内存。
从根本上讲,原因是因为内存总线具有一些特定长度,该长度远小于内存大小。
因此,CPU会从片上L1高速缓存中读取数据,目前这些数据通常为32KB。但是,将L1高速缓存连接到CPU的内存总线的高速缓存行大小的宽度要小得多。这将是128 位的数量级。
所以:
262,144 bits - size of memory
128 bits - size of bus
对齐错误的访问有时会重叠两条高速缓存行,这将需要读取一个全新的高速缓存才能获取数据。它甚至可能会一直丢失到DRAM。
此外,CPU的某些部分将不得不站起来,以将这两个不同的高速缓存行中的单个对象放在一起,每个高速缓存行都具有一个数据。在一行中,它将是非常高的位,而在另一行中,它将是非常低的位。
将有完全集成到管道中的专用硬件,该硬件可以将对齐的对象移动到CPU数据总线的必要位上,但是此类对象可能缺少对齐的硬件,因为使用这些晶体管加速正确优化的速度可能更有意义程式。
无论如何,无论有多少专用硬件(假想地和愚蠢地)专用于修补未对齐的内存操作,有时都需要进行第二次内存读取,这会减慢管道的速度。
@joshperry对这个问题给出了很好的答案。除了他的回答,我还有一些数字以图形方式显示了所描述的效果,尤其是2X放大。这是指向Google电子表格的链接,该链接显示了不同单词对齐方式的效果。此外,这是带有测试代码的Github要点的链接。测试代码改编自Jonathan Rentzsch撰写的文章,该文章引用了@joshperry。测试是在Macbook Pro上运行的,该Macbook Pro具有2.8 GHz四核Intel Core i7 64位处理器和16GB RAM。
x
和y
坐标是什么意思?