您的位置:首页 > 其它

内存对齐的影响

2015-07-29 11:07 267 查看
先说理论的为何要内存对齐?

1、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

2、 性能原因:经过内存对齐后,CPU的内存访问速度大大提升。

图一:



这是普通程序员心目中的内存印象,由一个个的字节组成,而CPU并不是这么看待的。

图二:



CPU把内存当成是一块一块的,块的大小可以是2,4,8,16字节大小,因此CPU在读取内存时是一块一块进行读取的。块大小成为memory accessgranularity(粒度)本人把它翻译为“内存读取粒度”。

假设CPU要读取一个int型4字节大小的数据到寄存器中,分两种情况讨论:

1、数据从0字节开始

2、数据从1字节开始

再次假设内存读取粒度为4。

图三:



当该数据是从0字节开始时,很CPU只需读取内存一次即可把这4字节的数据完全读取到寄存器中。

当该数据是从1字节开始时,问题变的有些复杂,此时该int型数据不是位于内存读取边界上,这就是一类内存未对齐的数据。

图四:



此时CPU先访问一次内存,读取0—3字节的数据进寄存器,并再次读取4—5字节的数据进寄存器,接着把0字节和6,7,8字节的数据剔除,最后合并1,2,3,4字节的数据进寄存器。对一个内存未对齐的数据进行了这么多额外的操作,大大降低了CPU性能。

这还属于乐观情况了,上文提到内存对齐的作用之一为平台的移植原因,因为以上操作只有有部分CPU肯干,其他一部分CPU遇到未对齐边界就直接罢工了。

我所遇到的问题:

在项目中要按协议解析一接收到的字串,从中提取数据。

环境为MSP430,裸奔程序。

刚开始使用的方法是,取串中对应数据段的首地址,将其强制转换成目标数据的数据类型指针,再取其值,将该值赋予目标对象。

以下是示意代码:

/*******************code start**********************/

// 找到指定数据的地址,pcSrcData指向传入的数据,MY_DATA_IDX是所需提取数据的相对地址

pcSrcData += MY_DATA_IDX;

// 提取我所需要的数据

fMydata = *((float *)pcSrcData);

/*******************code end**********************/

分析此代码,实际上我是要从任意地址上访问一个四字节的FLOAT数据,可能遭遇以下3种情景:

地址对齐,访问成功,此情况纯属巧合;
地址未对齐,CPU具有在未对齐情况下,CPU依然支持通过多次访问移位操作,对程序来说也可认为是成功的;
地址未对其,CPU也不支持未对齐情况下的纠错处理。

很不幸,也很幸运,在测试时我就遇到了第三种情况。但又不完全相同,此时CPU仍在访问,不过它对地址进行了调整,将其调整为四字节对齐,这样它是能正常访问了,可我的数据却提取错了。

处理方法:

/*******************code start**********************/

// fMydata = *((float *)pcSrcData);将此语句改为下面这句

memcpy(&fMydata , pcSrcData, sizeof(float));

/*******************code end**********************/

从这件事吸取的经验是态度上要谨慎再谨慎,不能有侥幸心理。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: