当我们在我们的代码中申明变量时,我们通常是不用考虑也不会去做所谓的内存对齐的,因为这个工作本身是属于编译器去完成的。那我们的变量为什么不按照大小顺序地存放而是非要做所谓内存对齐?这个问题其实也是属于一个冲突问题,主要原因是内存的粒度是字节,即每一个BYTE都有唯一的地址,而cpu访存是按机器字(比如32位机器一次访存会取4Byte,无论我们访问的变量是什么类型的,比如我们只是获取一个char型变量,应该会做数据截断),理论上来说我们应该能够访问任意一个地址开始的四个字节。但是实际硬件是不支持的,这里我也是看到别人有说这个点,虽然抽象上,内存空间就像一块大的连续的一维数组,就是在我们真实的内存访问中,其实我们的是多个内存芯片同时工作,如图(别人的图用一下)。连续的四个字节其实是存储在这四个芯片上的,我们的地址,会转为offset,然后四个芯片同时给出自己offset的内容,组成四个字节传回给我们。比如我们有一段空间是0x00到0x40,如果我们按照四字节对齐访问,那我们cpu能直接访问的就应该是0x04,0x08,0x0c......这样的地址。比如0x00存了一个char型的变量,那我们其实就应该是访问了0x00然后拿出了4byte,按照数据类型截下来了相应的大小的数据(比如char 就是一个byte)。那比如0x01处还有一个放了一个int型的数据,这个四字节数据的前三个,应该是芯片2,3,4的offset0给出,最后一个字节应该是芯片1的offset1给出,这样至少需要两个offset,硬件不支持的话,肯定是没法访问的,这其实应该是所谓硬件支持不支持的关键原因。如果对齐访问的话,我们访问是四字节对齐的,那这个地址我们是无法直接访问到的,如果发生了对这个位置的访问,就会引起cpu fault。
如果被访问的内存地址不按照被访问的数据类型的位宽对齐,称为非对齐访问。比如int型占4个字节,则访问int型数据的内存地址需要按照4字节对齐。那比如在内存空间中,0x00是放的一个char型,0x01-0x04放了一个int型的数据,如果我们这个时候通过0x01这个地址访问int型变量,这就叫非对齐访问。其实只要硬件支持都没有麻烦事儿,最麻烦的事情是内存存放数据的格式,和cpu访问方式冲突。举个例子,我们把数据挨着放,不做对齐,但是cpu仅支持对齐访问,这个时候就会出现大问题,所以即使对齐访问可能会牺牲一部分存储空间,为了访问的方便,即使用了较大的空间存放较小的数据,但是确实这样有利于cpu访问处理数据。编译器可能会把这样的访存,优化成两次对齐访问,即取0x00开始的后三个字节,加上0x04开始的第一个字节,凑成完整的一个四字节,两次访存加拼接,去避免这个问题。还有当不支持非对齐访问时,强制数据类型转换也容易引起这个问题,还是刚刚的例子,如果我们的0x01的数据还是一个char型,那其实直接访问0x01这个位置的一个字节这个操作是内存对齐的方式,是没问题的。但是我们如果强制转换这个地址的数据为一个int型的,就会产生上述的第一个问题,这个时候如果非对齐访问不支持就会引起cpu fault。
由上可见,内存对齐还是很重要的,从硬要求看,有的cpu不管你想不想,人家压根就不支持,从效率优化来看,非对齐访问即使得以被硬件所实现那效率一定也低于对齐访问,或者是假装支持,把非对齐访问拆分成两次对齐访问加数据合并,这也说明效率至少比对齐访问低两倍,只有在一些内存资源紧张的地方,我们才会采用这样的方式,用时间效率换空间。
标签:为什么,字节,我们,访问,内存,对齐,cpu From: https://www.cnblogs.com/luo-qi/p/16893721.html