我正试图解决为什么需要数据对齐/填充。来自维基百科:
“当现代计算机读取或写入内存地址时,它将以字大小的块进行此操作”
然而,我可以使用x86的movb
指令清楚地以字节分辨率移入和移出数据。我在这里缺少什么?
答案 0 :(得分:1)
这是一种常见的误解。 字节访问不要求对该缓存行的包含32位或64位块(或未缓存访问的内存)进行读取 - 修改 - 写入。请参阅Can modern x86 hardware not store a single byte to memory?。
单字节访问自动naturally aligned。这意味着与访问的宽度对齐,因此它不会跨越任何比自身更宽的边界。
单词加载或存储仍然是单个事务,除非它跨越缓存行边界(在这种情况下,CPU内部必须访问两个缓存行的相关部分)。所以这个引用只适用于机器字大小的访问。 (请注意,英特尔术语中的word
是16位,而不是现代x86 CPU的寄存器或总线宽度。这就是为什么我在上一句中说'#34;机器字&#34;'。< / p>
填充因此被添加到C中的结构不是因为字节访问对于字节大小的字段是低效的,而是使得宽于一个字节的对象自然对齐(例如{{1}跟随结构中的int
。
与字节访问不同,一些相对常见的平台支持或不支持直接未对齐访问,对于那些支持访问,未对齐访问可能效率较低,尤其是在跨越缓存行时。 C编译器将结构视为具有对齐要求,无论它们最对齐的成员是什么。例如由于char
成员,int
,char
和double
的结构将具有64位对齐,因此填充以使double
相对于struct也会在绝对意义上对齐它,因此struct成员总是保持自然对齐。
即使在没有未对齐访问权限的假设平台上,使用未对齐的对象也会使依赖于原子读取和写入的memory models的实现变得极为复杂,因为许多平台保证了这些操作的原子性only if they are aligned。
现代CPU以缓存行大小的块传输数据,而不仅仅是32位或64位字。除非您正在访问不可缓存的内存区域(例如,设备驱动程序中的内存映射I / O),否则您将获得实际的字节,16位,32位或64位访问越过外部公共汽车。
只要您不跨越64位边界,现代x86 CPU上的未对齐访问就不会受到任何惩罚。 (特别是在英特尔上,除非你越过缓存行边界,否则不会对未对齐的加载/存储造成任何惩罚)。
另请参阅How can I accurately benchmark unaligned access speed on x86_64标记wiki中的x86和性能调整链接。
答案 1 :(得分:-2)
字对齐的内存访问比字节对齐的内存访问快得多。这使得传输大块数据的速度更快。您可以寻址单个字节,但可能会从内存中读取一个字,并在内部缩减为一个字节。这使访问速度变慢。