代码之家  ›  专栏  ›  技术社区  ›  Fureeish

对齐方式对内存布局和布局的影响到底有多大?

  •  1
  • Fureeish  · 技术社区  · 6 年前

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

    显然,如果我们这样做的话

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

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

    我们得到同样的结果,也就是 10 .

    但行为不能完全相同,是吗?为什么它是可区分的?我试图寻找答案,然后跑向戈德博尔特,测试以下代码:

    #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] 就像我们在 对齐(int) 版本。

    请注意,我一般不理解装配。我不能写汇编,但我能读一些。据我所知,差异只是改变了内存加法器的偏移量,这将保持我们的位置。- 新的 预计起飞时间 int .

    但是它实现了什么呢?为什么我们需要那个?假设我们有一个 buffer 数组如下:

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

    现在,我想,在安置之后- 新的 ing int ( 有无 我们最终会得到这样的结果:

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

    哪里 x 表示 int (我们假设 sizeof(int) == 4 )

    但我一定错过了什么。还有很多,我不知道是什么。我们通过调整 缓冲区 int 适合对齐?如果我们 不要 对齐它吗?

    1 回复  |  直到 6 年前
        1
  •  1
  •   Matt Timmermans    6 年前

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

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

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

    推荐文章