首页 > 解决方案 > 为什么 C++ 标准库将大字符串缓冲区对齐为 32 字节?

问题描述

我正在反编译一个用 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 字节,然后将缓冲区的“真实”开头存储在其后面。这对我来说似乎是浪费空间,因为我不明白像这样对齐字符串缓冲区的开头的任何可能原因可能会带来任何性能改进。像这样对齐缓冲区有什么好处,还是需要更多的上下文来理解推理?

标签: c++c++-standard-library

解决方案


虽然我不知道您的编译器/库以这种方式运行的官方原因,但我当然可以看到一个直接的好处:SIMD。

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

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

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

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

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


推荐阅读