c++中的内存对齐(alignment)
不同的类型(eg. char, int, double)等有不同的对齐要求,在我的电脑上的值如下:
类型 | alignof(type)返回值 |
char | 1 |
int | 4 |
double | 8 |
也就是int类型的变量,其地址的值一定是4的整数倍;同理double类型变量的地址,其值要求是8的整数倍。
对于struct类型,其alignof的值是struct类中所有子类型对齐值中的最大值。
对齐对于struct类型size大小的影响
看两个例子
写法一
struct {
char c;
double f;
int n;
};
写法二
struct {
double f;
int num;
char c;
};
这两个struct中的元数相同,只是顺序不同。它们都是以8进行的对齐(和其内部的double类型的对齐值相同)。但使用sizeof观察两种写法的大小,第一个struct为24, 第二个为16。为什么呢?在写法一中,c只占1字节,但其后的f需要8对齐,因此从2到7字节会被padding,f占8字节(9到16),int占4字节(其后会padding4字节,应该也是和对齐有关,不确定),因此整体size为24字节。而第二种写法,不同元数中间没有padding,只在c后会有padding,整体更加紧凑。
结论:struct中元数的顺序对于其size也有影响。
c++中的函数
alignof | 查看类型的对齐值 |
alignas | 更改类型的对齐值 |
alignment对于性能的影响
从系统角度,考虑一下如果double类型没有alignment的限制,那么它的其实地址为任意值。考虑到cache line一次能获取64bytes的值,那么可能需要两次cache load才能完整获取到该double的值。因此alignment保证了所有基础类型都能在一次cache line中加载到寄存器中。
从coding角度,我们可以使用alignas函数更改struct类型的alignment值。比如一个struct的size正好是64bytes,但其默认的alignment值可能为8。当我们强制其alignment为64后,每次获取该struct元数则只需要一次cache line的操作,性能无疑会有所提升。特别是多个线程同时访问struct array时。
参考文献
https://en.cppreference.com/w/cpp/language/object#Alignment
http://cenalulu.github.io/linux/all-about-cpu-cache/