访问元素之间填充的 16 字节对齐的连续内存中的元素是否比内存中紧密排列的元素更快?

Is accessing elements on a 16 byte aligned contigous memory with paddings between elements faster than tightly packed elements in memory?

想象一下,如果我们有一个自定义的内存分配器,我们将其初始化为 64,并且每当我们想要在其中构造一个新元素时,分配器都会将每个元素的起始地址对齐为 16 字节对齐的地址.

例如:如果分配器在堆上分配了一块从地址0x00 to 0x40开始的内存,当我们在里面分配4个32位整数时,这块内存他们的地址是:0x00, 0x10, 0x20 and 0x30.

现在让我们想象另一个自定义分配器,它也分配一个 16 字节对齐的内存。例如,如果我们说大小为 15,则分配的内存地址范围为 0x00 to 0x10.

但是这一次,这个分配器不会将每个元素的起始地址对齐为 16 字节对齐的内存,而是将元素并排放置。

为了我们的论证,让我们再次假设我们试图在这个分配器的缓冲区内构造四个 32 位整数。这次,这些整数的起始地址将为 0x00, 0x04, 0x08 and 0x0c.

我的问题是;这些分配器中的哪一个会导致更少的 CPU 指令,(抱歉,如果我对此有误,因为它可能会导致相同的指令)或者会在 64 位系统上产生更快的读取时间?

16 位处理器

假设我有一个喜欢获取 16 位数据的处理器。

当数据在 16 位边界上对齐时,处理器只需进行一次提取:

  +---+---+  
4 | a | b |  
  +---+---+  

在一次获取中,处理器可以获得 ab(8 位量)。

如果我们有不在 16 位边界上的数据,处理器将不得不进行两次提取,然后进行一些位移和屏蔽以生成 16 位字。

  +---+---+  
2 |   | a |  
  +---+---+  
4 | b |   |  
  +---+---+  

在上面的示例中,16 位数据位于内存位置 3。为了获取数量 ab,处理器必须在地址 2 处进行取指(以获取 a 数量),然后在地址 4 处取数以获取 b 值。这是 2 次提取而不是 1 次,更不用说将 ab 变成一个 16 位字的额外努力了。

最终结果是您的程序变慢了。效率损失是否可以忽略不计是另一回事。

32 位处理器

32 位处理器可以最有效地获取 32 位数据。因此,当处理器被告知获取不在 32 位边界上的数据时,它必须至少进行一次额外获取,类似于上述 16 位场景。

一些 32 位处理器可能经过优化也可以执行 8 位提取,因此要提取 3 个字节(3 x 8 位),处理器将进行 3 次 8 位提取。 (虽然它可以连接以进行 32 位提取,然后使用位移和掩码将 8 位量放入单独的寄存器中)。

内存对齐和地址解码

让我们首先了解地址范围中的每个 2 的幂都有一个地址线。访问内存时,基本技术是将地址转换为二进制并相应地设置地址行。

然而,围绕 PCBA 板布线所有这些地址线变得复杂(且成本高昂)。某些平台可能会消除 16 位对齐的第一地址线和 32 位对齐的第一和第二行(画图,您会看到这些线不用于关联的提取)。因此,如果内存在 32 位边界上对齐,访问未对齐的项目将需要从内存中进行多次提取,因为内存可能没有解码所有地址行。这会减慢你的程序。减速是否可以忽略不计是另一回事。