访问元素之间填充的 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 |
+---+---+
在一次获取中,处理器可以获得 a
和 b
(8 位量)。
如果我们有不在 16 位边界上的数据,处理器将不得不进行两次提取,然后进行一些位移和屏蔽以生成 16 位字。
+---+---+
2 | | a |
+---+---+
4 | b | |
+---+---+
在上面的示例中,16 位数据位于内存位置 3。为了获取数量 ab
,处理器必须在地址 2 处进行取指(以获取 a
数量),然后在地址 4 处取数以获取 b
值。这是 2 次提取而不是 1 次,更不用说将 a
和 b
变成一个 16 位字的额外努力了。
最终结果是您的程序变慢了。效率损失是否可以忽略不计是另一回事。
32 位处理器
32 位处理器可以最有效地获取 32 位数据。因此,当处理器被告知获取不在 32 位边界上的数据时,它必须至少进行一次额外获取,类似于上述 16 位场景。
一些 32 位处理器可能经过优化也可以执行 8 位提取,因此要提取 3 个字节(3 x 8 位),处理器将进行 3 次 8 位提取。 (虽然它可以连接以进行 32 位提取,然后使用位移和掩码将 8 位量放入单独的寄存器中)。
内存对齐和地址解码
让我们首先了解地址范围中的每个 2 的幂都有一个地址线。访问内存时,基本技术是将地址转换为二进制并相应地设置地址行。
然而,围绕 PCBA 板布线所有这些地址线变得复杂(且成本高昂)。某些平台可能会消除 16 位对齐的第一地址线和 32 位对齐的第一和第二行(画图,您会看到这些线不用于关联的提取)。因此,如果内存在 32 位边界上对齐,访问未对齐的项目将需要从内存中进行多次提取,因为内存可能没有解码所有地址行。这会减慢你的程序。减速是否可以忽略不计是另一回事。
想象一下,如果我们有一个自定义的内存分配器,我们将其初始化为 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 |
+---+---+
在一次获取中,处理器可以获得 a
和 b
(8 位量)。
如果我们有不在 16 位边界上的数据,处理器将不得不进行两次提取,然后进行一些位移和屏蔽以生成 16 位字。
+---+---+
2 | | a |
+---+---+
4 | b | |
+---+---+
在上面的示例中,16 位数据位于内存位置 3。为了获取数量 ab
,处理器必须在地址 2 处进行取指(以获取 a
数量),然后在地址 4 处取数以获取 b
值。这是 2 次提取而不是 1 次,更不用说将 a
和 b
变成一个 16 位字的额外努力了。
最终结果是您的程序变慢了。效率损失是否可以忽略不计是另一回事。
32 位处理器
32 位处理器可以最有效地获取 32 位数据。因此,当处理器被告知获取不在 32 位边界上的数据时,它必须至少进行一次额外获取,类似于上述 16 位场景。
一些 32 位处理器可能经过优化也可以执行 8 位提取,因此要提取 3 个字节(3 x 8 位),处理器将进行 3 次 8 位提取。 (虽然它可以连接以进行 32 位提取,然后使用位移和掩码将 8 位量放入单独的寄存器中)。
内存对齐和地址解码
让我们首先了解地址范围中的每个 2 的幂都有一个地址线。访问内存时,基本技术是将地址转换为二进制并相应地设置地址行。
然而,围绕 PCBA 板布线所有这些地址线变得复杂(且成本高昂)。某些平台可能会消除 16 位对齐的第一地址线和 32 位对齐的第一和第二行(画图,您会看到这些线不用于关联的提取)。因此,如果内存在 32 位边界上对齐,访问未对齐的项目将需要从内存中进行多次提取,因为内存可能没有解码所有地址行。这会减慢你的程序。减速是否可以忽略不计是另一回事。