2

我试图弄清楚为什么需要数据对齐/填充。来自维基百科:

“当现代计算机读取或写入内存地址时,它将以字大小的块执行此操作”

然而,我可以使用 x86 的movb指令以字节分辨率清楚地来回移动数据。我在这里想念什么?

4

2 回答 2

1

这是一个普遍的误解。 字节访问不需要对该高速缓存行(或用于未高速缓存访​​问的内存)的包含 32 位或 64 位块的读取-修改-写入。请参阅现代 x86 硬件不能将单个字节存储到内存吗?.

单字节访问会自动自然对齐。这意味着与访问的宽度对齐,因此它不会跨越任何比自身更宽的边界。


一个字加载或存储仍然是一个单一的事务,除非它跨越缓存线边界(在这种情况下,CPU 必须在内部访问两个缓存线的相关部分)。因此,该引用仅适用于机器字大小的访问。(请注意,word在英特尔术语中是 16 位,而不是现代 x86 CPU 的寄存器或总线宽度。这就是我在上一句中说“机器字”的原因。)

因此,填充被添加到 C 中的结构中并不是因为字节访问对于字节大小的字段效率低下,而是因为比一个字节宽的对象自然对齐(例如,结构中的int后续 a char)。

与字节访问不同,一些相对常见的平台支持或不支持直接非对齐访问,而在那些支持的平台上,非对齐访问可能效率较低,尤其是在跨越高速缓存行时。C 编译器将结构视为对其最对齐的成员具有对齐要求。例如intchar, 和的结构double由于成员的原因将具有 64 位对齐double,因此填充以对齐double相对于结构的对齐也将在绝对意义上对齐它,因此结构成员始终保持其自然对齐。

即使在没有未对齐访问惩罚的假设平台上,具有未对齐对象也会极大地使依赖于原子读取和写入的内存模型的实现复杂化,因为许多平台只有在它们对齐时才能保证这些操作的原子性。


现代 CPU 以高速缓存行大小的块传输数据,而不仅仅是 32 位或 64 位字。除非您正在访问不可缓存的内存区域(例如,设备驱动程序中的内存映射 I/O),在这种情况下,您实际上会通过外部获得字节、16 位、32 位或 64 位访问公共汽车。

只要您不跨越 64 位边界,现代 x86 CPU 上的未对齐访问就不会受到惩罚。(特别是在英特尔上,除非您跨越缓存线边界,否则不会对未对齐的加载/存储进行处罚)。

另请参阅如何准确地对 x86_64 上的未对齐访问速度进行基准测试,以及标签 wiki中的性能调整链接。

于 2018-01-22T07:53:44.420 回答
-2

字对齐的内存访问比字节对齐的快得多。这使得传输大块数据的速度更快。您可以寻址单个字节,但可能会从内存中读取一个字并在内部减少为一个字节。这使得访问速度变慢。

于 2013-05-15T01:19:16.530 回答