内存未对齐导致性能降低及其处理

  内存未对齐是指 cpu要读取N字节数据,但数据的起始地址不能被N所整除,导致效率降低,甚至异常的出现。例如当cpu读取一个int类型的变量,而变量地址是0x10005的时候就产生未对齐访问。

自然对齐:


    N字节的数据类型需要放在起始地址为被N整除的地址这称为自然对齐。并不是所有体系结构的计算机带都要求自然对齐,有的可以指定对齐方式。但是为了达到好的可移植性编写代码的时候最好都用自然对齐方式。

未对齐的影响


    未对齐的内存访问在不同的体系结构中会有不同的效果:有一些计算机可以透明的处理未对齐访问,但效率会降低很多;有一些计算机会产生异常,然后调用一个异常处理程序改正错误;有一些计算机产生异常,但是没有办法校正错误;有一些计算机则没有办法处理未对齐访问,而直接读取不正确的内存地址,造成难以察觉的代码漏洞。

编译器的影响:


    一般情况下编译器可以通过填充(padding)使得数据结构满足对齐要求。例如一下结构:


    Struct foo{


        U16 field1;


        U32 field2;


        U8 field3;


}


假设数据起始地址是0x10000.编译器在field1后填充2个字节使field2保持对齐,最后在field3后填充3个字节使整个数据结构4对齐,全部结构体占用空间为12字节。


导致未对齐访问的原因:


既然编译器能够自动对齐数据结构,导致内存未对齐访问的原因是什么?未对齐访问的


必要条件:指针强制类型转换且小数据转大数据。例如:


unsigned int compare_ether_addr(const u8 *addr1, const u8 *addr2)


{


    const u16 *a = (const u16 *)addr1;


    const u16 *b = (const u16 *)addr2;


    return ((a[0] ^ b[0]) | (a[1] ^b[1]) | (a[2] ^ b[2])) != 0;


}


Addr1指针所在地址可能是奇地址开头,强制类型转化给指针a,导致未对齐的内存访问。Mips架构的cpu不能很好的处理未对齐访问,会导致程序出错退出。X86可以处理未对齐,但是如果未对齐访问太多效率也会下降很多。不管是Mips,还是X86,都希望所操作地址是对齐的,因为这样可以最快速地处理数据。不过X86平台可以很容易很快速地处理不对齐的情况,而Mips一旦遇到地址不对齐的变量就会抛出exception,从而调用一大段后续处理代码,继而消耗大量的时间。


解决方案

应该使用memcpy()函数进行代替指针强制类型转换。



Linux内核对unaligned access的处理方法



可以配置/proc/sys/debug/alignment的参数以配置内核对内存未对齐访问的处理方式,总共有6中可选,"ignored","warn","fixup","fixup+warn","signal","signal+warn",可以配置的值和含义:


0 warn 触发内核打印消息包含程序名称、Pid、PC寄存器值,指令,地址,出错码。


1 fixup 内核尝试修复未对齐访问异常,这会导致性能降低。


2 signal 这个配置会引发SIGBUS错误,程序退出。


请查看内核说明(cat /proc/cpu/alignment)以确定选择那种处理方式所对应的数字。


内存未对齐处理示例


问题描述:


编译webkit源码后在Freeman 9150(mips架构,sh4linux)运行出现unaligned access,SIGBUS错误,程序退出:


     Unaligned userspace access in "QtTestBrowser" pid=1636 pc=0x2a012f6a ins=0x01ce
     Unaligned userspace access in "QtTestBrowser" pid=1636 pc=0x29f4ad7a ins=0x5111
     Sending SIGBUS to "QtTestBrowser" due to unaligned access (PC 29f4ad7a PR 29f4ac6e)
解决办法:


1、  在linux终端输入ulimit –c unlimited开启core dump功能。


2、  修改/proc/sys/kernel/core_uses_pid,使用pid作为core dump文件的扩展名;修改/proc/sys/kernel/core_pattern(例如/corefile/core%p)设置core文件保存位置和文件格式。


3、  使用gdb查看出错信息,定位代码。 gdb ./ QtTestBrowser  core.xxxx, 使用bt命令即可看到程序出错的地方。


4、查看源码,修改错误, 注意查看指针转化的情况。用memcpy()代替相关代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值