所以基本上我很难理解数据对齐。我不明白为什么在 64 位架构上,例如将 4 字节数据存储到地址 0x0、0x4、0x8、0xC 的倍数很重要。CPU 的提取是否从字大小的每个倍数开始(这里是 8 个字节)?为什么 2 字节数据必须存储在 0x0、0x2、0x4、0x6、0x8、0xA、0xC、0xE 地址?即使存储在 0x1,CPU 也可以在一个时钟内加载 2 字节数据……那么为什么它应该在地址 0x0、0x2、0x4、0x6、0x8、0xA、0xC、0xE。
另外,如果 CPU 缓存行例如是 64 字节,那么如果数据在地址 0x...00 和 0x...40 之间不重叠,为什么我要关心数据对齐?这很令人困惑...
对于小于用于访问内存的字大小的n字节对象,确保对象与n字节的倍数对齐可确保对象不会跨越字(假设n是字大小的一个因子)。
假设一台机器有一个八字节内存接口:每个对齐的八字节序列都可以通过一次传输操作从内存中读取或写入内存。因此,从 0 到 7 的所有八个字节都可以在一次传输中从内存中读取,从 8 到 15 的所有八个字节也可以在一次传输中从内存中读取,依此类推。但仅读取两个字节 7 和 8 就需要两次传输,因为机器架构无法在一次传输中读取任何八个字节;它只能读取从 8 的倍数开始的一个八字节序列。
现在考虑一个四字节对象类型,比如
int
。当有人声明一个这样的数组时,当从地址 2 开始的int a[7];
时候会发生什么a
?对象a[0]
位于字节 2、3、4 和 5 中。对象a[1]
位于字节 6、7、8 和 9 中。依此类推。a[0]
可以在一次内存传输中读取。CPU 可以在一次传输中获取字节 0-7,并取出a[0]
字节 2-5。但是,a[1]
不能在一次内存传输中读取。CPU 无法在一次传输中读取字节 6、7、8 和 9。它需要发出一次传输来获取字节 0-7,然后发出另一次传输来获取字节 8-9。当我们要求四字节对象类型具有四字节对齐时,我们会阻止这种情况。那么数组
a
就不int a[7];
能从字节 2 开始。它必须从字节 0、4、8、12 等开始。例如,如果它从字节 4 开始,那么a[0]
在字节 4-7 中,位于八字节集 0-7 内。a[1]
在 8-11 中,位于 8-15 内。a[2]
在 12-15 中,位于 8-15 内。因此,每个元素都a
在一个八字节对齐字节集内。因此,内存访问将比没有a
四字节对齐时更高效。