c++内存对齐

1.为什么要内存对齐


  内存存取粒度:大部分处理器并不是按字节块来存取内存的.它一般会以双字节,四字节,8字节,16字节甚至32字节为单位来存取内存,我们将上述这些存取单位称为内存存取粒度。

  以4字节作为存取粒度的处理器,只能从地址为4的倍数的内存开始读取数据。

  假如一个int变量存放在从地址1开始的四个字节地址中,该处理器去取数据时,第一次要先从0地址开始读取第一个4字节块,剔除不想要的字节(0地址);第二次从地址4开始读取下一个4字节块,同样剔除不要的数据(5,6,7地址),最后留下的两块数据合并放入寄存器,这会非常影响性能。

  归根结底是编译器想通过空间换时间,通过适当增加padding,使每个成员的访问都在一个指令里完成,而不需要两次访问再拼接,提高内存的访问效率。

2.内存对齐规则


  对齐系数:#pragma pack(n)。

  对齐单位:min(#pragma pack(n),结构体中最长数据类型长度)。

  内存对齐规则:

    [1]内部对齐:第一个数据成员放在offset为0的地方,以后每个成员相对于结构体首地址的offset都是 min(该成员大小,对齐单位)的整数倍,如有需要编译器会在成员之间加上填充字节。

    [2]外部对齐:结构体的总大小为对齐单位的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。

  因此看一个结构体大小时,首先根据内部对齐规则累加每个变量的大小,之后再根据外部对齐算出总大小。

  例如对于:

#pragma pack(2)
struct aa{
        char a;
        char b;
        int c;
        char d;
        long long e;
        char f;
};

   首先:对齐单位 = min(#pragma pack(2),sizeof(long long)),因此对齐单位是2。

      a放到offset == 0的位置,因为0是【min(a成员大小,对齐单位) == 1】的整数倍。

      b放到offset == 1的位置,因为1是【min(b成员大小,对齐单位) == 1】的整数倍。

      c放到offset == 2的位置,因为2是【min(c成员大小,对齐单位) == 2】的整数倍。

      d放到offset == 6的位置,因为6是【min(d成员大小,对齐单位) == 1】的整数倍。

      e放到offset == 8的位置,因为8是【min(e成员大小,对齐单位) == 2】的整数倍。

      f放到offset == 16的位置,因为16是【min(f成员大小,对齐单位) == 1】的整数倍。

      此时共占用了17个字节,而整个结构体需要是对齐单位(2)的整数倍,因此整个结构体大小是18。

    

 

 

 

posted on 2019-03-19 15:10  能量星星  阅读(138)  评论(0编辑  收藏  举报

导航