比如32位总线,数据线d7:0与地址4*n的存储单元连接,数据线d15:8与地址4*n+1的存储单元连接,……。对齐要求将长度为4的变量放在4*n的地址,这样可以一次读取这4个字节;否则就需要读2次,再拼接到一起。
对齐是由底层硬件环境决定的,严格来说是为了方便CPU内存访问寻址。C/C++与其它编程语言相比是允许开发者可以直接操作内存,所以才要知晓对齐的概念。至于说有什么好处就说不上了,这个本来就是“底层规则”,所有的的程序语言不管是通过什么方式运行起来的,归根到底还是在内存对数据进行操作。
以上是个人经验理解,表达不完全正确,仅供参考哈?
对齐是硬件定位方式引起的。不同的CPU和机器架构,对内存或硬件地址的读写方式,会以一定的距离跳跃,一次读入若干位的数据。举个例子,如果它一次读入32位即4字节的数据,那么当程序设计数据使用1字节的字符串时,或2字节的整数时,则后续字节的数据可能被略过了,要重新再读写(一次读写以4字节为单元,数据需要代码整理),这样表面看起来节省了数据占用空间,实际上却降低了执行效率。所以一般的编译器,会根据机器具体环境优化编译结果,把数据取齐为对应的长度。比如上面的例子,对齐长度是4字节的环境,虽然程序员代码规定使用2字节的整数,编译器编译的结果也是实际使用4字节,除非你把2个这样的整数组合为结构类型,又如结构是由1个2字节整数和1个单字节字符组成,这个结构体实际占用的空间是4字节,有1字节是未初始化的空间(不要想当然编译器一定会给你初始化)。这就是对齐的概念,喜欢直接透视底层的程序员必须要有相关意识,因此对C程序员来说,某些自以为高效的操作实际上可能是陷阱,尤其是那些mem操作类操作库函数。
对齐既有好处也有坏处,都在这个本质上反应,高效的代价是你必须付出更谨慎的代码思考。程序执行快,思考的过程必然长,代码写得快,效率必然有风险,不是效率低就是bug多。上帝很公平,省力不省功,时间与空间对立统一。
内存对齐是个硬件问题,本身并不是一个C/C++的问题,只是因为C/C++能够直接操作内存指针,才有了对此优化的可能性。
严格的说,对齐(alignment)甚至不是一个CPU问题,而是MMU(内存/缓存)问题。
简单说,对齐有助于提升缓存使用效率。cache的设计,每条line都是一个对齐的空间,比如32字节。用它们的地址低位索引。如果你读写到一个地址和当前cache line失配,就会引发该line的write back和reload,也就说,有性能成本。而且,如果你熟悉芯片设计的话,就知道这个成本是惊人的。很多软件工程师可能意识不到,多数情况下,cpu只有极少的时间在执行指令,大部分时间都在干等,等缓存。
所以,对于有性能优化要求的程序来说,多数情况下优化内存是第一位的。非对齐的内存访问,非常容易造成一次刷新两条cache lines,此时很可能造成本来还很快有用的数据被洗出缓存,不但增加了本次操作的成本,更重要的是,下次还得再次把洗出的数据装回来,这个代价很大,更糟糕的是,下次这笔操作很可能继续导致新的有用数据被洗出,循环往复。
据我观察,如今99%的程序员对cpu内存架构几乎一无所知,代码几乎完全不考虑性能。的确,多数场合这也无所谓。反正,硬核的活儿都给那剩下1%的人干了。