类的内存对齐

7
我正在使用游戏引擎架构这本书来开发一个内存管理器。 目前我正在阅读关于内存对齐的内容(在书和网上),但不确定如何正确地为类使用对齐。我理解内存对齐的概念(例如,4字节数据块应位于以0x0、0x4、0x8或0xC结尾的地址上),但是在书中的allocateAligned()函数中有一条注释说对齐必须为2的幂次方。如果我有一个包含两个int和一个char的类,sizeof(class)告诉我,该类大小为12字节。那么,你会把32作为对齐方式来传递吗?这不是浪费内存并可能导致碎片化吗?我的问题是,如何正确地对齐类,你能详细地解释一下吗(如果你想对更大的数据块进行对齐会发生什么),并且对于较大的数据块进行对齐是否有意义(因为处理器一次只获取8个字节,如果我没记错的话)?

16 也是二的幂。 - chepner
我从未听说过这个二的幂规则。最近在课堂上学习了对齐,看起来这个类应该是12字节(填充以匹配“int”的大小)。 - gsgx
“对齐”是2的幂,但“大小”不是。 - Kerrek SB
1
聚合体的对齐通常是其元素的最大对齐,而不是它们的总和。 - n. m.
2个回答

7

类型的对齐方式永远不能大于类型的大小。这是因为在数组中,元素之间不能有填充。

同样重要的是,类型的对齐方式可能会比类型的大小

让我们考虑你的类类型:它有三个成员,两个4字节整数和一个2字节整数。假设4字节整数的对齐方式为4字节,2字节整数的对齐方式为2字节(这很常见)。在这种情况下,你的类类型的对齐方式只有4字节。它可以位于任何4字节边界上,并且它的每个成员都将被正确对齐。

这就是为什么你的类类型有两个字节的填充的原因:12可以被四整除,但10不行。如果你的类没有填充,它的大小只有10字节,在元素的数组中,一半的对象会对齐不正确。


如果我有一个类,其中包含一个占用12个字节的实例成员,会发生什么? - user1347198
@immerhart:对齐仍然可能是四个字节。更大/更严格的对齐仅由奇怪的数据类型(也许是long double?)引起,而不是通过将成员塞入struct来实现。 - aschepler
在这种情况下,该类型的对齐方式将为1字节、2字节或4字节(这些是12的2次幂因子)。 - James McNellis
好的,我想我明白了。有人能告诉我,为什么SIMD(16字节)应该与16字节对齐而不是4字节? - user1347198
SSE指令要求其操作数在16字节边界上对齐。因此,SSE数据类型需要在这样的边界上对齐。我不知道为什么SSE指令需要超对齐数据。 - James McNellis

2

类型的对齐方式可以比其大小小,但不能比其大小大。在典型的32位实现中,您的

struct X {
    int a;
    int b;
    char c;
};

你可能会发现 Xsizeof(X) == 12alignof(X) == 4。显然,你无法每四个字节就有一个 X,因为它们会重叠,但是对齐意味着 0x10000x10040x10080x100c都是你可能开始一个 X 的潜在位置。
请注意,sizeof 返回的类型大小始终是对齐的倍数,因为 sizeof 指定数组元素之间的字节数,你不希望数组中的第一个条目对齐而第二个却没有对齐。

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