C++ 为什么128位变量应与16字节边界对齐

C++ 为什么128位变量应与16字节边界对齐,c++,c,memory-management,assembly,x86,C++,C,Memory Management,Assembly,X86,正如我们所知,x86CPU有一个64位的数据总线。我的理解是CPU不能访问任意地址。CPU可以访问的地址是其数据总线宽度的整数倍。为了提高性能,变量应该从这些地址开始(对齐),以避免额外的内存访问。与4字节边界对齐的32位变量将自动与8字节(64位)边界对齐,后者对应于x86 64位数据总线。但为什么编译器将128位变量与16字节边界对齐?不是8字节边界 谢谢 让我把事情说得更具体些。编译器使用变量的长度来对齐它。例如,如果一个变量的长度为256位,编译器会将其与32位边界对齐。我不认为有任何一

正如我们所知,x86CPU有一个64位的数据总线。我的理解是CPU不能访问任意地址。CPU可以访问的地址是其数据总线宽度的整数倍。为了提高性能,变量应该从这些地址开始(对齐),以避免额外的内存访问。与4字节边界对齐的32位变量将自动与8字节(64位)边界对齐,后者对应于x86 64位数据总线。但为什么编译器将128位变量与16字节边界对齐?不是8字节边界

谢谢


让我把事情说得更具体些。编译器使用变量的长度来对齐它。例如,如果一个变量的长度为256位,编译器会将其与32位边界对齐。我不认为有任何一种CPU有那么长的数据总线。此外,普通的DDR内存一次只能传输64位数据,尽管有缓存,内存怎么能填满CPU更宽的数据总线呢?或者仅通过缓存?

一个原因是X86上的大多数SSE2指令要求数据128位对齐。做出这个设计决定是出于性能原因,也是为了避免硬件过于复杂(因此速度慢、体积大)。

有太多不同的处理器型号,所以我将仅从理论和一般方面回答这个问题

考虑一个由16字节对象组成的数组,其起始地址是8字节的倍数,但不是16字节。让我们假设处理器有一个8字节的总线,如问题中所示,即使有些处理器没有。但是,请注意,在数组中的某个点上,其中一个对象必须跨越页面边界:内存映射通常在4096字节边界开始的4096字节页面中工作。对于八字节对齐的数组,数组的某些元素将从一页的字节4088开始,一直到下一页的字节7

当程序试图加载跨越页面边界的16字节对象时,它无法再执行单个虚拟到物理内存映射。它必须对前八个字节执行一次查找,对后八个字节执行另一次查找。如果加载/存储单元不是为此而设计的,则该指令需要特殊处理。处理器可能会中止执行该指令的初始尝试,将其划分为两个特殊的微指令,并将其发送回指令队列执行。这会使指令延迟许多处理器周期

此外,正如Hans Passant所指出的,对齐与缓存交互。每个处理器都有一个内存缓存,缓存通常被组织成32字节或64字节的“行”。如果加载16字节对齐的16字节对象,并且该对象位于缓存中,则缓存可以提供一条包含所需数据的缓存线。如果从非16字节对齐的数组加载16字节对象,则数组中的某些对象将跨越两条缓存线。加载这些对象时,必须从缓存中提取两行。这可能需要更长的时间。即使不需要更长的时间就可以得到两条缓存线,可能是因为处理器设计为每个周期提供两条缓存线,这也会干扰程序正在做的其他事情。通常,一个程序将从多个地方加载数据。如果负载是有效的,处理器可以一次执行两个。但如果其中一个需要两条缓存线而不是普通缓存线,则会阻止其他加载操作的同时执行


此外,某些指令明确要求对齐地址。处理器可能会更直接地分派这些指令,绕过一些修复没有对齐地址的操作的测试。当这些指令的地址被解析并发现未对齐时,处理器必须中止它们,因为修复操作已被绕过。

“我们知道,X86 CPU有64位数据总线”-这不是真的。x86没有说明数据总线的大小。现代处理器实际上有更大的数据总线宽度。处理器不从数据总线读取数据,而是从缓存读取数据。需要16字节对齐,以避免跨越缓存线边界。@Mysticial我认为最流行的x86 CPU目前有64位数据总线,不是吗?@iqapple Nope。Intel Core 2、Nehalem和Sandy Bridge处理器具有128位宽的加载/存储端口。虽然不确定AMD的,但我认为他们自K8以来也有128位宽的加载/存储端口。缓存级别和内存之间的数据总线甚至很大。(想想缓存线大小)32位变量与4字节边界对齐,在任何CPU上都没有必要将它们与8字节边界对齐。我知道你是对的,即使有些点对我来说是深奥的。在我看来,这个答案大部分是正确的,但它本身与“但是为什么编译器将128位变量与16字节边界对齐?”。这个问题的答案很简单,硬件要求这样做,编译器这样做不是因为效率更高,而是因为任何其他方法都不起作用。当你说”考虑一个16字节对象的数组,它起始于一个八字节但不是16字节的多个地址。“嗯,这是不起作用的(因为CPU硬件不支持它),而不管数组是否跨越页面边界。实际上这取决于这个问题由“变量”表示的意思。“。我想到了128个变量,比如_m128i。如果是关于
structfoo{charx[128];}
那么我同意Eric的说法。@user2151446:硬件确实支持通过
movups
等指令进行未对齐的访问。C实现支持未对齐的16字节SIMD对象是完全可行的。使用这种实现的程序通常会很慢,但它们可以工作。因此,选择是否使用对齐地址不是一种可能性或硬件支持,而是一种效率