为什么 malloc 是 16 字节对齐的?
Why is malloc 16 byte aligned?
GNU 文档指出 malloc
在 64 位系统上与 16 字节的倍数对齐。这是为什么?
如果我的理解是正确的,寄存器和所有指令都对最大 8 字节宽的值进行操作。因此,似乎需要 8 字节对齐。
备注:
- 我看到一些评论者说这只是为了减少内部碎片,这没有多大意义,因为文档指出他们专门为
x86_64
[=23= 移动到 16 字节对齐]
x86_64 使用 xmm 寄存器(大量使用 -- 所有 fp 内容都在 xmm 寄存器中完成,因为 8087 fp 寄存器已弃用),并且 xmm 寄存器需要 16 字节对齐才能(高效)访问。
所以 x86_64 中的大部分内容(包括由 malloc 分配的堆栈和堆)都组织为始终 16 字节对齐,因此编译器始终可以自由使用 'aligned' 指令涉及 xmm 寄存器,不需要使用(可能较慢)未对齐指令。
在较新的硬件上,编译器甚至不需要麻烦使用对齐指令——当内存对齐时,未对齐指令与对齐指令一样快。
x86-64 System V 使用 x87 作为 long double
,80 位类型。并将其填充为 16 字节,使用 alignof(long double) == 16
因此 long double 永远不会跨越缓存行边界。 (无论是否值得,IDK;SSE2 可能是廉价支持 16 字节对齐的动机之一)。
但是无论如何,SSE 的东西并不是对 alignof(max_align_t) == 16
的唯一贡献(它设置了允许 malloc return 的最小对齐)。
__m128i
的存在根本不会直接 对 max_align_t
有贡献,例如 32 位 C 实现以较低的 malloc 保证支持它.当然,支持 AVX 的系统上 __m256i
的存在并没有增加分配器的对齐保证。 ()。但对于自动和手动矢量化来说,malloced 内存对于 movaps
来说足够对齐,尤其是在较旧的 CPU 上,当 x86-64 是新的并且 movups
即使内存对齐时也会受到惩罚。如果编译器只看到 float*
,则很难利用该保证,您可以将指针传递到分配的中间。但是,如果它可以看到输出数组的 malloc
,它就知道如果自动向量化写入新分配的 space.
的循环,它将对齐
顺便说一句,ISO C 会让 malloc
用于小分配(比如 1 到 15 个字节)return 对齐较少 space,因为 space 仍然可以用于容纳任何适合的类型。在 C 语言中,对象不能要求比其大小更多的对齐方式。 (例如,你不能 typedef 一个 int
总是必须在缓存行的开头,或者如果你做 sizeof 用填充扩展。)
GNU 文档指出 malloc
在 64 位系统上与 16 字节的倍数对齐。这是为什么?
如果我的理解是正确的,寄存器和所有指令都对最大 8 字节宽的值进行操作。因此,似乎需要 8 字节对齐。
备注:
- 我看到一些评论者说这只是为了减少内部碎片,这没有多大意义,因为文档指出他们专门为
x86_64
[=23= 移动到 16 字节对齐]
x86_64 使用 xmm 寄存器(大量使用 -- 所有 fp 内容都在 xmm 寄存器中完成,因为 8087 fp 寄存器已弃用),并且 xmm 寄存器需要 16 字节对齐才能(高效)访问。
所以 x86_64 中的大部分内容(包括由 malloc 分配的堆栈和堆)都组织为始终 16 字节对齐,因此编译器始终可以自由使用 'aligned' 指令涉及 xmm 寄存器,不需要使用(可能较慢)未对齐指令。
在较新的硬件上,编译器甚至不需要麻烦使用对齐指令——当内存对齐时,未对齐指令与对齐指令一样快。
x86-64 System V 使用 x87 作为 long double
,80 位类型。并将其填充为 16 字节,使用 alignof(long double) == 16
因此 long double 永远不会跨越缓存行边界。 (无论是否值得,IDK;SSE2 可能是廉价支持 16 字节对齐的动机之一)。
但是无论如何,SSE 的东西并不是对 alignof(max_align_t) == 16
的唯一贡献(它设置了允许 malloc return 的最小对齐)。
__m128i
的存在根本不会直接 对 max_align_t
有贡献,例如 32 位 C 实现以较低的 malloc 保证支持它.当然,支持 AVX 的系统上 __m256i
的存在并没有增加分配器的对齐保证。 (movaps
来说足够对齐,尤其是在较旧的 CPU 上,当 x86-64 是新的并且 movups
即使内存对齐时也会受到惩罚。如果编译器只看到 float*
,则很难利用该保证,您可以将指针传递到分配的中间。但是,如果它可以看到输出数组的 malloc
,它就知道如果自动向量化写入新分配的 space.
顺便说一句,ISO C 会让 malloc
用于小分配(比如 1 到 15 个字节)return 对齐较少 space,因为 space 仍然可以用于容纳任何适合的类型。在 C 语言中,对象不能要求比其大小更多的对齐方式。 (例如,你不能 typedef 一个 int
总是必须在缓存行的开头,或者如果你做 sizeof 用填充扩展。)