|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?注册
x
本帖最后由 charlie_zhang 于 2017-3-16 18:39 编辑
目前网络上很多对齐的资料都是从写软件的角度来说明,写C代码应该对齐,例如举例定义一个结构体,内部各个变量不同的定义顺序,可能会导致结构体占用不同的存储空间,而一般嵌入式系统对存储空间又特别敏感,所以这个问题在各种嵌入式软件工程师笔试及面试时都会涉及。
涉及两个问题:
1. 为何需要对齐?
2. 从码农角度,如何编写空间优化的代码?
对于上述两个问题,由于网络上回答这两个问题的都是软件工程师,一般侧重于回答第二个问题,而对于第一个问题则很少涉及,就算谈到第一问题,也是浅浅很谈,这篇文章尝试去回答第1个问题。
编译器为何会安排变量对齐存储呢?
答1:直接百度这样的问题,基本的解释都是”效率的需要“,即提高访问存储器的速度,顶多举例子说一个平台只会从偶地址取数据,而如果一个半字16bit数据data[15:0]被放置在{2N-1,2N}上,对于little endian系统来说,data[7:0]放置在2N-1地址上;data[15:8]放置在2N地址上。那么当CPU尝试读取此数据时,至少要发起两次读操作才能完全获取该变量,很明显影响了效率,本来一次就能完成的事情,现在偏偏要分两次。
OK,上面的回答能否让你信服呢?
很明显不能让我信服,我会有疑问,为何cpu要从偶数地址取数据?为什么不能从奇数地址取数据,直接从奇数地址取16bit数据不就反驳了答1中的思路了吗。
回答2:
1. 理想状况:
其实我们的目标是实现一个快速的计算机系统,理想情况下,我们希望cpu提出访问存储器请求,存储器经过一定的时延,访问就能够完成。
这里cpu访问存储器的地址希望是任意的;存储器反应的时间希望是最短的即接近是0,并且随机从任意地址读取任意字节数据。
2. 现实存储器状况:
存储器特性:很明显理想的存储器是不存在的,首先是访问存储器的形式,一般都是以类似1024*32bit = M*N形式给出,1024表示存储单元,32表示每个存储单元存储32bit数据,这是对存储器一种逻辑抽象。表示这个存储器每次访问最多访问32bit数据,不会再多;同时每次访问的32bit数据也不是从任意地址开始的,而是从满足address % 4 =0 的地址开始的。
或许你会问,为什么采用这种形式的存储器呢,为何不能做到从任意地址读取32bit:我不是做存储器ip设计的,但是猜想(或者肯定)要实现这个目标肯定是可以的,但是存储器的复杂程度将大幅度增长,同样位数存储器,为了实现能够从任意地址一次访问32bit数据,存储器将变得无比复杂。
或许你会问,为什么用1024*32bit,而不用512*64bit形式即每个存储单元有更多位数呢,这样cpu发来任意地址,即使存储器中的变量不对齐,但是只要N足够大,一次读取存储器,端口出现Nbit数据,cpu只要取希望读取的相应字节数据即可,虽然不能完全避免边界时需要访问两次,但是在很大程度上缓解了访问速度的问题了:我想说,这种想法有一个前提,即1024*32bit存储器和512*64bit存储器访问一次所需要的时间是相同的,从存储器本身角度来说,的确可能是这样的,但是输出数据端口将从32bit增加到了64bit,如果你想继续增大N,存储器的数据口将变得更加拥挤;同时对于常见的8/16/32/64位计算机系统来说,每次能够处理的数据位数是有限的,Nbit的数据需要额外的选择电路选择哪些数据才是cpu真正需要的,同时cpu也要发出多位的选择控制信号,对cpu设计也是一个挑战。
上述所有这些的目的只是为了节约一点不大的存储器空间,甚至这些存储空间可以通过合理的编译器优化以及程序员优秀的编码使得浪费的存储器空间降低到最小甚至为零。
3. cpu状况
通过对存储器特性的大致分析,同时以32位的ARM体系结构为例,就知道我们没有必要要求cpu发出访问任意连续32bit数据的请求,因为这样的请求由于存储器的局限,不可能一次访问就获得回复。因此cpu访问只要求满足address % 4= 0的地址的数据访问请求,减小了很多cpu设计的复杂性。
你可能会问:以32位系统为例子,地址{4*N,4*N+1,4*N+2,4*N+3}上的4个字节,可以被cpu一次访问即可得到,那么在这个4个字节空间内,是否可以将以将16bit变量放置在{4*N+1,4*N+2}上呢?虽然这并不符合alignment规则,但是从存储器角度来说,的确可以一次就访问到了,并没有影响效率呀?
OK,这个时候cpu说话了:"我弱弱的提一个要求,我可不可以不访问{4*N+1,4*N+2}这样的16bit数据。我想每次访问只能有7种访问方式:
a: 地址4*N+0单字节数据
b: 地址4*N+1单字节数据
c: 地址4*N+2单字节数据
d: 地址4*N+3单字节数据
e: 地址{4*N+0,4*N+1}双字节数据
f: 地址{4*N+2,4*N+3}双字节数据
f: 地址{4*N+0,4*N+1,4*N+2,4*N+3}四字节数据
听到cpu这样说话,计算机系统设计者就问,你为何有这样的请求,cpu说:“这样的话我就能进一步精简内部逻辑,可以简化我好多工作,我非常讨厌对地址{4*N+1,4*N+2}2个字节这样的数据访问” ,计算机系统设计者想了想:好吧,就让编译器多干点活吧,提出了现在的“对齐alignment对齐”概念,让编译器在多到对齐的同时也尽量减小对存储器空间的浪费,同时也告诉码农:“你写代码时注意点,记住对其的概念,减小对存储器对浪费”
总结:通过上述分析,可以知道对齐概念的出现,时计算机设计者权衡了设计复杂性,现实可能性,速度与成本(存储器大小)之后作出的最优化化选择。 |
|