§ 参考资料 共 1 条
内存对齐指的是:数据在内存中存储时的起始地址受到限制,同时会影响结构体或类的大小
CPU 访问内存并不是一个字节一个字节地读,而是以 Chunk 为单位,如果不对齐,那么可能需要多读一个 Chunk
对齐值
分为自身对齐值、指定对齐值和有效对齐值三个
自身对齐值通常等于数据类型的大小
对于内置类型,就等于该类型的大小,如:
char: 自身对齐值为 1int: 自身对齐值为 4double: 自身对齐值为 8
对于结构体或者类,它的自身对齐值为其成员中最大的那个自身对齐值
指定对齐值是由编译器或者预处理指令强制指定的对齐系数
- 默认情况下,64 位操作系统默认的对齐数为 8,32 位的为 4
- 可以使用
#pragma pack(n)指令,更改指定对齐值为n
有效对齐值是编译器最终执行的对齐数值
- 有效对齐值 = 指定对齐值 与 自身对齐值 的较小值
- 对于结构体或者类,有效对齐值为其成员中最大的那个有效对齐值(和上面是等价的)
对齐
对于结构体内部的各个成员,每个成员的起始位置,完全取决于它自己的有效对齐值
- 结构体中第一个成员的偏移量为 0
- 每个成员偏移量必须是该成员的有效对齐值的整数倍
在确定各个成员的位置后,需要确定当前结构体的大小
- 根据对齐值规则可以求出当前结构体的有效对齐值。最终总大小必须是有效对齐值的整数倍,如果不够会在末尾填充字节
- 结构体或者类至少占用 1 个字节
C++ 中的相关函数和编译器拓展
C++ 标准
alignof:返回自身对齐值
alignas:增大自身对齐值(不能比默认值小)
// 强制结构体起始地址 32 字节对齐
struct alignas(32) Data {
float data[8];
};
// 也可以用于变量
alignas(64) int cache_line_isolated_var;
注意几个函数的 align 参数都是有效对齐值
std::align(align, size, buffer_ptr, buffer_size):在 Buffer 中查找计算并返回一个满足特定对齐要求的指针地址
std::aligned_alloc(align, size):在堆上分配对齐的内存
std::assume_aligned<align>(ptr):告诉编译器“我保证这个指针已经是 X 字节对齐的了,请生成更高效的指令
编译器拓展
MSVC:
#pragma pack(n):改变指定对齐值
__declspec(align(n)):增大自身对齐值,与 alignas 一致
_aligned_malloc、_aligned_free
GCC/Clang:
__attribute__((packed)):压缩对齐,结构体的自身对齐值设置为 1,并且内部无视对齐规则,紧密排列
__attribute__((aligned(n))):增大自身对齐值,与 alignas 一致
posix_memalign(ptr_of_ptr, align, size)