相信大部分人都知道内存对齐,都知道变量要8字节对齐,性能高。但其根本原理是什么?可能有人会说,因为缓存是以8字节为单位进行的。读者,你很聪明,这就是原因之一。不过今天要挖掘的是一个更底层的原理,下面我们就到内存的物理构成中去寻找答案吧!内存物理结构前面我们说过,内存是由芯片组成的。每个芯片内部由8个bank组成。它的结构如下图所示:而每一个bank就是一个二维平面上的矩阵,我们在上一篇文章中提到过。矩阵中的每个元素存储1个字节,即8位。内存寻址方式那么对于我们应用程序中内存中连续的8个字节地址,比如0x0000-0x0007,是不是位于bank上呢?直观的感觉,应该是在第一岸吧?事实上,它不是。从程序员的角度来看,0x0000-0x0007这连续地址实际上位于8个bank中,每个bank只保存一个字节。从物理上讲,它们不是连续的。下图很好地说明了现实。您可能想知道这是为什么,原因是电路的效率。内存中的8个bank可以并行工作。如果要读取地址0x0000-0x0007,每个bank工作一次,把要的数据放在一起,IO效率会更高。但是如果它存在于银行里,那么银行就只能自己干活了。只能串行读取,需要读取8次,所以速度会慢很多。结论因此,内存对齐的底层原因是内存IO是以8字节64位为单位进行的。对于64位数据宽度的内存,如果CPU也是64位的CPU(现在的电脑基本都是这样),内存IO每次获取数据时,从8个芯片各读取一个字节同一行并将它们放在一起。从内存地址0开始,一次IO可以读出0-7个字节的数据,也可以一次读出8-15个字节的数据。再比如,如果指定要获取0x0001-0x0008,也是8个字节,但不是0开头,那么内存是怎么工作的呢?没有什么好办法,内存得工作一次取出0x0000-0x0007,再取出0x0008-0x0015,两次的结果返回给你。CPU和内存IO的硬件限制导致无法同时跨两个数据宽度进行IO。这会减慢你的应用程序,这是计算机的一点惩罚,因为你不了解内存对齐。延伸一:其实编译器和链接器会自动为开发者对齐内存,尽量帮你保证一个变量不会跨列寻址。但他不可能是完美的。延伸2:其实在内存硬件层上,还有操作系统层。操作系统还管理CPU的一级、二级和三级高速缓存。不知道大家有没有印象,我们在上一篇文章中说过,缓存中的CacheLine也是64字节,是内存IO的整数倍,这样就不会浪费内存IO了。练内功:内存部分:1.带你了解内存对齐的底层原理2.内存随机访问比顺序访问慢,让你深刻理解内存IO流程3.从DDR到DDR4,内存核心频率基本一致没太大进步4.实测内存有顺序IO和随机IO的访问延迟差异5.揭穿内存厂商的“谎言”,实测内存带宽的实际表现6.NUMA架构下内存访问延迟的区别!7.PHP7内存性能优化精髓8.一个内存性能提升的项目实践9.挑战Redis单实例内存最大极限,“遭遇”NUMA陷阱!我的公众号是“练内功练功”。在这里,我不是简单地介绍技术理论,也不是只介绍实践经验。而是理论联系实际,用实践加深对理论的理解,用理论提高技术实践能力。欢迎关注我的公众号,分享给你的朋友吧~~~
