咱们来了解一下内存的物理构造,通常内存的外形图片以下图:程序员
图1 内存外形图缓存
一个内存是由若干个黑色的内存颗粒构成的。每个内存颗粒叫作一个chip。每一个chip内部,是由8个bank组成的。其构造以下图:ide
图2 chip内部构成性能
而每个bank是一个二维平面上的矩阵,前面文章中咱们说到过。矩阵中每个元素中都是保存了1个字节,也就是8个bit。spa
图3 bank内部构成操作系统
那么对于咱们在应用程序中内存中地址连续的8个字节,例如0x0000-0x0007,是从位于bank上的呢?直观感受,应该是在第一个bank上吗?其实不是的,程序员视角看起来连续的地址0x0000-0x0007,其实是位于8个bank中的,每个bank只保存了一个字节。在物理上,他们并不连续。下图很好地阐述了实际状况。orm
图4 连续8字节在内存中实际分布blog
你可能想知道这是为何,缘由是电路工做效率。内存中的8个bank是能够并行工做的。若是你想读取地址0x0000-0x0007,每一个bank工做一次,拼起来就是你要的数据,IO效率会比较高。但要存在一个bank里,那这个bank只能本身干活。只能串行进行读取,须要读8次,这样速度会慢不少。图片
因此,内存对齐最最底层的缘由是内存的IO是以8个字节64bit为单位进行的。 对于64位数据宽度的内存,假如cpu也是64位的cpu(如今的计算机基本都是这样的),每次内存IO获取数据都是从同行同列的8个bank中各自读取一个字节拼起来的。从内存的0地址开始,0-7字节的数据能够一次IO读取出来,8-15字节的数据也能够一次读取出来。ip
换个例子,假如你指定要获取的是0x0001-0x0008,也是8字节,可是不是0开头的,内存须要怎么工做呢?没有好办法,内存只好先工做一次把0x0000-0x0007取出来,而后再把0x0008-0x0015取出来,把两次的结果都返回给你。CPU和内存IO的硬件限制致使没办法一次跨在两个数据宽度中间进行IO。这样你的应用程序就会变慢,算是计算机由于你不懂内存对齐而给你的一点点惩罚。
扩展1:事实上,编译和连接器会自动替开发者对齐内存的,尽可能帮你保证一个变量不跨列寻址。可是他不能作到十分完美。
扩展2:其实在内存硬件层上,还有操做系统层。操做系统还管理了CPU的一级、二级、三级缓存。不知道你有没有印象,咱们前面的文章说太高速缓存里的Cache Line是64字节,它是内存IO单位的8倍,不会让内存IO浪费。