C++内存对齐

5

我了解到在C++中,当声明变量时,如果你想获得最佳的缓存读取效果,内存应该保持其自然对齐方式。例如:

int a; // memory address should end in 0x0,0x4,0x8,0xC
int b[2]; // 8 bytes 0x0,0x8
int b[4]; // 16 bytes 0x0

但是在实践中,这些变量并不遵循“自然对齐”规则,一个16字节的变量存储在以0xC结尾的内存地址,为什么会这样呢?


3
数组不关心对齐,只有单个元素需要对齐。 - Quentin
可能需要引用确切的案例。 - Glenn Teitelbaum
其实并没有具体的情况,我只是在做实验。我发现无论变量大小如何,它们都是4字节对齐的,除非是1字节的数据类型。只是好奇为什么会这样。 - Student123
4个回答

7
自然内存对齐通常指的是单个变量的对齐,而不是变量数组。因此,一个由4字节整数组成的数组(如上所述)自然对齐到4字节边界,而不是16字节边界。
自然内存对齐通常涉及CPU的载入/存储指令的结构和实现方式,而不是缓存行的大小。CPU并不一次性加载整个数组(除了矢量加载)。因此,CPU并不关心它正在加载的整数是否是数组的一部分。
矢量加载会同时加载小型数组,通常具有更严格的对齐要求。例如,在x86上进行对齐的矢量加载,必须将项对齐到16字节。

我也尝试了使用16字节的数据类型,但它们仍未对齐到0x0。我只能说无论大小如何,一切都是4字节对齐的。是否有些编译器或不同的CPU会以不同的方式处理呢? - Student123
@Student123:你需要使用_aligned_malloc来为数组和对象获取对齐内存。 - user276648

4
C++不会将任何内容对齐到缓存行,因为从所有意义上讲,它并不知道有缓存存在。如果您想要将某些内容对齐到16字节边界,请尝试在堆上使用posix_memalign(),或者(如果使用GCC)在栈上使用int x __attribute__ ((aligned (16)))。在C++11中,有alignas specifier。但我不知道如何使用new()调用具有保证对齐的函数。

你可以编写自己的 operator new() 并强制对齐。 - Glenn Teitelbaum
我说的对吗?只要一块内存是4字节对齐的,CPU就会充分利用数据,并且不需要多次读取任何4字节变量吗? - Student123
@Student123 我猜这取决于CPU。一般来说,我认为这是一个好的经验法则。我知道现代x86微架构不再惩罚未对齐的加载。 - hayesti

2

无法保证对齐


2
@LegalizeIt 这就是完整的答案,OP声称对齐应该是某个值,我说没有保证。其余的答案已在第一条评论中给出。一个int类型的地址可能是奇数,虽然很少见,但确实有可能。 - Glenn Teitelbaum
@scohe001 这是一个答案。 - Glenn Teitelbaum

1
根据Intel® 64和IA-32架构优化参考手册(第B.4.5.2节Assists),跨越两个页面的32字节AVX存储指令需要一次辅助操作,大约需要150个周期。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接