CPU
内存对齐指的是对象首地址的位置是某个数值(alignment)的整数倍, 比如按4字节对齐,那么这个对象的首地址会是4的整数倍(0,4,8 …)。
假如一个对象要求按alignment对齐,那么我们如何保证其所在的内存地址就是alignment的整数倍?
- 堆(malloc/new)
下面的代码可以看到,new出来的地址是16的整数倍(malloc也一样,不过这里测试数据不严谨,应该说是max_align_t
的整数倍,具体就可以翻阅malloc的文档),16的整数倍肯定也是Data的对齐属性8的整数倍,但是如果Data的对齐属性是32,那么new出来的内存首地址就不一定是32的整数倍,这里就需要开发者自己去实现malloc_align(), free_align(),当然gcc和msvc会有实现好的memalign(size, alignment)。
struct alignas(8) Data
{
char i;
char j;
char k;
};
int main()
{
Data* demo = new Data();
std::cout << "Data align = " << alignof(Data) <<std::endl;
std::cout << "Data size = " << sizeof(Data) <<std::endl;
std::cout << "address of demo: " << (reinterpret_cast<uintptr_t>(demo)) % 16 << std::endl;
std::cout << "address of demo: " << (reinterpret_cast<uintptr_t>(demo)) % 32 << std::endl;
}
//print
Data align = 8
Data size = 8
address of demo: 0
address of demo: 16
- 栈
根据下面的代码可以测试出来,当Data在栈上的时候,对象的首地址会是其对齐属性的整数倍,这个工作应该是编译器做的,所以一旦编译结束后地址应该就确定了。
struct alignas(512) Data
{
char i;
char j;
char k;
};
int main()
{
Data demo ;
std::cout << "Data align = " << alignof(Data) <<std::endl;
std::cout << "Data size = " << sizeof(Data) <<std::endl;
std::cout << "address of demo: " << (reinterpret_cast<uintptr_t>(&demo)) % 512 << std::endl;
std::cout << "address of demo: " << (reinterpret_cast<uintptr_t>(&demo)) % 1024 << std::endl;
}
// print
Data align = 512
Data size = 512
address of demo: 0
address of demo: 512
CPU数据结构
对于数据结构而言,
struct Test
{
char a;
int b;
char c;
}
假如机器默认对齐值是4,那么偏移是[0,4,5]。现在问题来了,时候需要padding呢?其实padding多少是根据该类型的数组[1]的值确定的,主要是为了保证[1]的a,b,c还符合对齐规则,为此总结min(default, max_size(Test)), 这个玩意可以证明,数组[1]中的a,b,c都符合对齐规则,很神奇。这里Test的对齐值应该是4,所以sizeof(Test)=12, alignof(Test)=4.我们知道C++提供一个alignas去对类型设定。
struct alignas(1) Test
{
char a;
int b;
char c;
}
根据上面推导我们知道,类型对齐值应该是4,但是这里强制设置了1,如果按照1去对其的话,数组[1]中的b偏移是13,这就不对,所以这里编译器还是会按4去设定,忽略程序员提供的错误信息。
struct alignas(8) Test
{
char a;
int b;
char c;
}
当设定为8的时候,这里[1]中a的偏移是16,那么b的偏移是20符合偏移规则,所以8符合条件,那么编译器就会接受这个设定,所以alignof(Test)=8, sizeof(Test)=16。综上,对于结构体而言sizeof取决于数组[1]中的各个变量能否满足对齐规则,即使程序员强行指定,如果不符合的话编译器也不接受的。
GPU
cudaMalloc 类似于malloc,cudaMalloc的对齐地址是256。
类似于alignas ,cuda中使用__align__来给结构设定对其属性。