【C语言】简单而不严谨地理解内存对齐

   

当再次看到自己半年前说的“有时间我会把内存对齐这个补上滴”,内心可是满满的懒惰不想动呀[doge]......

下面是正文————————————————

一.为什么要内存对齐

       众所周知,当CPU想从内存中取出数据时,会先将地址通过 地址总线 传输给内存,内存通过地址找到对应的数据,而后将数据通过 数据总线 传送至CPU中去。

       假设地址总线和数据总线都分别有8根(如不加以说明,以下例子全部设定为地址总线 = 数据总线 = 8),那么CPU最大所能找到的地址范围是[0,255](PS:操作系统是32位的,那么数据总线长度也得是32位的,地址总线至少也得是32位的,所以32位的地址总线最少可以表达的地址数是4294967296种(2的32次方),换成GB(兆字节)就等于4GB。32位的操作系统最大能支持的内存是4GB,因为超过之后就找不到地址了。)

       当CPU发送一个地址给内存去数据时,我们小脑袋瓜里面以为的内存取数据是这样的:

        有这样一块连续的内存,内存拿到地址之后,从左往右逐个逐个取出来放入数据总线中去,假如需要提取八个字节,那么内存需要取八次数据。而实际上,为了提高读取速度,真实的内存是按照这样子来设计的:

        一条内存条里面有好多个chip,每个chip里面又分了好多个bank(俗称内存颗粒),每个bank里面有根据行和列将数据按照地址方式进行存储。而当CPU传入一个地址时,内存会根据地址找出相应的行和列,在bank里面进行数据查找,而这个地址对应的并不是一个数据,而是八个数据(一般一个内存颗粒里面会有八个bank,当然也有更多bank的内存条):

        传入的地址会在每个bank的同一个位置里面取出数据,将这八个数据组合在一起成为我们小脑瓜上以为的连续的内存,其中取八个数据只需要取一次,比前面说的取八次要快很多。而如果我们有一个2字节的数据,前七个字节都放满数据了,按照我们小脑袋瓜的理解,这个2字节的数据理论上会放在第八第九位:

       这样存储会出现一个问题,因为这2个字节不在同一块地址里面,所以需要取出来的时候会出现取两次的情况,现取前一块内存的最后一个字节,再取下一块内存的第一个字节,将两个字节拼在一起组成一个数据,这样取数据会大大地降低内存的读取速度,为了提高速度,正确的方法应该是从下一块内存开始存,前面的内存应该空出来一个地方:

         为了提高读取速度,将各种变量按照合适的大小和合适的地址进行存储的方法就是内存对齐

 

二.怎样内存对齐

       在知道什么是内存对齐后,我们来看看怎么进行内存对齐,内存对齐主要还是要看数据类型的大小以及地址位置。根据编译器或者操作系统等各种不可抗拒因素,每个数据类型的大小都会有所差异,下面以 char 为 一字节 ,int 为 四字节 ,long long为八字节大小进行说明,以结构体为例,我们需要遵守的两个原则:

1.内存相对地址需要是数据类型大小的整数倍

2.存完所有内存后,最后一个数据的内存相对地址要是这堆数据中最类型大小最大的类型的整数倍

例子1:

按照内存对齐原则,应该这样存储数据:

char 类型占一个字节,所以从内存的第一个位置存:

如果没有内存对齐,那个后面紧跟着的int 类型将会被存在地址为"1" 的位置去,但是实际上进行了内存对齐后,地址“1”并不是int类型大小"4"的整数倍(1%4 = ?),所以数据不能存在这里,需要往后面找,一直到地址”4”(4%4 = 0),满足条件,所以int类型的数据将从这里开始存:

后面的longlong 类型的数据应该从地址"8"开始存起,计算一下发现当前地址恰好是longlong类型的整数倍(8%8 = 0),可以继续存,所以又一直往后存八个字节:

而当存完所有数据之后,还没完,还要看看最后一个地址是多少(例子中为15),(15%8 =?)显然不满足原则的第二点,所以需要往后面空,空到满足条件为止,然后发现地址“16”刚好可以(16%8 = 2),所以最后整个结构体大小就确定好了:

例子2,将例子1 换下顺序:

char 类型占一个字节,所以从内存的第一个位置存:

地址“1”并不是int类型大小"8"的整数倍(1%8 = ?),所以数据不能存在这里,需要往后面找,一直到地址”8”(8%8 = 0),满足条件,所以longlong类型的数据将从这里开始存:

后面的int 类型的数据应该从地址"16"开始存起,计算一下发现当前地址恰好是int类型的整数倍(16%4 = 3),可以继续存,所以又一直往后存四个字节:

而当存完所有数据之后,还没完,还要看看最后一个地址是多少(例子中为19),(19%8 =?)显然不满足原则的第二点,所以需要往后面空,空到满足条件为止,然后发现地址“24”刚好可以(24%8 = 3),所以最后整个结构体大小就确定好了:

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章