数据对齐的原理

从底层探究数据对齐

Posted by mengxun on February 28, 2019

数据对齐

在x86-64硬件上写C的struct的时候,如果声明了如下结构:

struct {
    int i;
    char c;
    int j;
} S1;

从表面看,这个struct所占的内存空间应该是9(4+1+4)个bytes,但是实际上它却占了12bytes的空间。

之所以会出现这种现象,是因为编译器在字段cj之间填充了3字节的间隙,这样的话j的偏移量就是8而不是5,就能满足每个字段的偏移量都是4的整数倍,再加上起始字节的地址是4的整数倍,就能保证每个字段的地址都是4的整数倍,这就是所谓的数据对齐。

那么,为什么要数据对齐呢?简单来讲,是因为一般情况下,访问的内存地址为偶数时,性能会比较高。

原理

CPU是通过数据总线对存储器(内存)进行读写的,要实现读写则需要将存储器芯片的数据引脚与数据总线进行一一连接。而当存储器芯片的字长小于数据总线宽度之时,就需要两个或多个存储器芯片进行扩展,以匹配上数据总线的宽度。

8086为例,8086的数据总线是16根,地址总线是20根,可寻址的存储空间为1MB。而平时CPU既需要存取字节又需要存取字,为了实现这一点,8086的存储器就一分为二,分成了两个存储体,一个为奇存储体(存奇数地址),另一个为偶存储体(存偶数地址),需要访问字节时就只访问其中一个存储体,访问字时就两个存储体都访问,完美实现了访问字和访问节的需求。

除了这两个存储体之外还有两个选通信号A0(标示偶存储体)和BHE(标示奇存储体),分别用来标示这两个存储体。最重要的重点在于:

  • 信号A0是用地址总线的最低位进行表示的,而信号BHE则是用一条高八位数据总线引出线(可以看作一条额外的地址线)来进行表示的。

  • 当地址总线最低位为0时,则地址总线所表示的地址必定是偶数地址,否则就是奇数地址。

从这两点可以得出,地址总线的最低位同时有两个作用:1. 表示地址是奇数还是偶数,2. 表示选通信号A0是否有效(0有效,1无效)。那么:

  • 当地址总线最低位为0时,访问的地址是偶数地址,如果此时BHE信号也有效,那么就相当于访问两个字节(字),否则就只是访问字节。

  • 当地址总线最低位为1时,访问的地址为奇数地址,但是也代表着选通信号A0无效,无法访问偶数地址,这样就造成了当访问奇数地址的时候就无法访问偶数地址,也就是说在访问字的时候需要两个总线周期才可以(一次访问奇数地址,一次使BHE无效以只访问偶数地址)。

以上只是16位CPU的情况,另外还有32位、64位等CPU,原理也是一样的,只是存储体和选通信号多了一些,更详细的可以参见微机原理里的内容(下面有链接)。

总结

通过以上可以总结出两点:

  • 内存返回的是字节、字还是双字这些都是由选通信号决定的,选通信号是由数据总线的高位和地址总线的低位表示的

  • 数据对齐是为了一次把想访问的数据都访问到,不用再第二次访问,从而提升性能

参考

《微型计算机组织与接口技术》 p102~p106

《微机原理与接口技术》 p174~p175

《深入理解计算机系统》(第3版) p190~p191