c++ - 对齐究竟如何影响内存布局和新布局的行为?

标签 c++ memory-alignment placement-new memory-layout alignas

我们阅读了很多关于对齐及其重要性的文章,例如放置 new 用法,但我想知道 - 它如何准确地改变内存布局?

显然,如果我们这样做

char buffer[10];
std::cout << sizeof buffer;

alignas(int) char buffer[10];
std::cout << sizeof buffer;

我们得到相同的结果,即 10

但是行为不可能完全一样,对吗?怎么区分呢?我试图寻找答案并跑到 godbolt,测试以下代码:

#include <memory>

int main() {
    alignas(int) char buffer[10];
    new (buffer) int;
}

在 GCC 8.2 下并且没有优化,导致以下汇编:

operator new(unsigned long, void*):
    push    rbp
    mov     rbp, rsp
    mov     QWORD PTR [rbp-8], rdi
    mov     QWORD PTR [rbp-16], rsi
    mov     rax, QWORD PTR [rbp-16]
    pop     rbp
    ret
main:
    push    rbp
    mov     rbp, rsp
    sub     rsp, 16
    lea     rax, [rbp-12]
    mov     rsi, rax
    mov     edi, 4
    call    operator new(unsigned long, void*)
    mov     eax, 0
    leave
    ret

让我们通过删除 alignas(int) 部分来稍微更改代码。现在,生成的程序集略有不同:

operator new(unsigned long, void*):
    push    rbp
    mov     rbp, rsp
    mov     QWORD PTR [rbp-8], rdi
    mov     QWORD PTR [rbp-16], rsi
    mov     rax, QWORD PTR [rbp-16]
    pop     rbp
    ret
main:
    push    rbp
    mov     rbp, rsp
    sub     rsp, 16
    lea     rax, [rbp-10]
    mov     rsi, rax
    mov     edi, 4
    call    operator new(unsigned long, void*)
    mov     eax, 0
    leave
    ret

值得注意的是,它仅在 lea 指令上有所不同,其中第二个参数是 [rbp-10] 而不是 [rbp-12] ,正如我们在 alignas(int) 版本中所做的那样。

请注意,我通常不懂汇编。我不会写汇编,但我能读懂它。据我了解,差异只是改变了内存地址的偏移量,这将保存我们的位置-newed int

但是它实现了什么?为什么我们需要那个?假设我们有一个 buffer 数组的“通用”表示,如下所示:

[ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ]

现在,我假设,在放置 newint(有或没有对齐)之后,我们最终会像这样:

[x] [x] [x] [x] [ ] [ ] [ ] [ ] [ ] [ ]

其中 x 表示 int 的单个字节(我们假设 sizeof(int) == 4)。

但我一定遗漏了什么。还有更多,我不知道是什么。通过将 buffer 对齐到 int 合适的对齐方式,我们究竟实现了什么?如果我们这样对齐会怎样?

最佳答案

在某些架构上,类型必须对齐才能使操作正常进行。例如,int 的地址可能需要是 4 的倍数。如果它不是这样对齐的,那么对内存中的整数进行操作的 CPU 指令将无法工作。

即使当数据没有很好地对齐时一切工作,对齐对于性能仍然很重要,因为它确保整数等不会跨越缓存边界。

当您将 char 缓冲区与整数边界对齐时,它不会影响 placement new 的工作方式。它只是确保您可以使用 placement new 将 int 放在缓冲区的开头,而不会违反任何对齐约束。它通过确保缓冲区的地址是 4 字节的倍数来实现这一点。

关于c++ - 对齐究竟如何影响内存布局和新布局的行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54337626/

相关文章:

c++ - 调用复制 ctor 和另一个 ctor

c++ - Opencv C++ 灰度图像黑色像素化结果(替换图像值时)

c - "double"类型是否需要 8 字节对齐?

c++ - 使用 placement-new 运算符和复制构造函数代替赋值运算符

c++ - 放置和非放置分配器

c++ - 创建独立于构造函数参数的对象指针

c++ - 使用assert(f<char, int>()) 编译错误

c++ - 错误 : cannot open file 'boost_atomic-vc120-mt-1_58.lib' boost libs on Qt Windows8

c++ - 该标准对未对齐的内存访问有何规定?

c - 是否可以强制 GCC 在 .rodata 中填充字符串常量