为什么 C++ 标准库将大字符串缓冲区对齐到 32 字节?

Why is the C++ standard library aligning large string buffers to 32 bytes?

我正在反编译一个用 C++ 构建的二进制文件,我注意到当缓冲区大小 ('alloc_bytes') >= 0x1000 时,分配和重新分配字符串缓冲区将对齐到最接近的 32 字节。这是我的反编译代码说明了这一点:

if (alloc_bytes < 0x1000)
{
    new_char_buffer = STD__allocate_bytes(alloc_bytes)
}
else
{
    void *new_buffer_start = STD__allocate_bytes(alloc_bytes + 0x20 + 0x07)

    new_char_buffer = new_buffer_start + 0x20 + 0x07
    new_char_buffer = new_buffer_start & 0xffffffffffffffe0 // round to lower 0x20
    *(new_char_buffer -0x08) = new_buffer_start // guaranteed valid memory after rounding because we allocated 0x20 (32) plus an additional 0x07 (7)
}

在这里,如果 alloc_bytes 足够大,字符串缓冲区的开头会四舍五入到较低的 0x20 字节,然后缓冲区的“真实”开头存储在它后面。这对我来说似乎是在浪费 space,因为我不明白像这样对齐字符串缓冲区的开头可能会带来任何性能改进的任何可能原因。像这样对齐缓冲区有什么好处,还是只需要更多的上下文来理解推理?

虽然我不知道您的 compiler/library 这样做的官方原因,但我肯定可以立即看到好处:SIMD。

SI指令MData 指令是允许您获得非常便宜的并行性的操作。但是,在您或更可能是您的编译器可以有效利用它们之前,它们确实有一些要求。

其中一个要求是在 SIMD 寄存器中加载内存要求加载的内存比常规单值操作更严格对齐。

像这样的大缓冲区经常用于可以利用这些指令的算法中,并且往往比小缓冲区有更大的好处。

此外,由于缓冲区已经相当大,因此“浪费”的比例很小。浪费少量内存以确保计算速度提高 4* 倍,这对我来说确实是一个合理的权衡。

N.B. 其实不是4次。自动矢量化循环通常有一个前缀和后缀部分来处理未对齐的数据,因此真正的好处只是跳过前缀并直接跳转到矢量化循环。但就您的问题而言,这些技术细节并不重要。