内存未对齐(Unaligned access ...)导致性能降低及其处理

内存未对齐访问可能导致性能下降甚至异常,特别是在某些计算机体系结构中。编译器通常通过填充来确保数据对齐,但强制类型转换可能导致未对齐访问。在MIPS架构中,未对齐访问会导致程序错误,而X86可以处理但效率降低。解决方案包括使用memcpy()函数代替指针强制类型转换,并可通过Linux内核配置来处理未对齐访问异常,如警告、修复或触发SIGBUS错误。
部署运行你感兴趣的模型镜像

 

个人在ST710x上遇到过这个问题,确实可行。

unsigned int len = *(unsigned int*)(buf + 8);

--->memcpy(&len, buf + 8, sizeof(int)); // 解决不对齐问题


引用地址http://blog.youkuaiyun.com/qwyang/article/details/7479268,附原文:

内存未对齐是指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内核对unalignedacess的处理方法:

可以配置/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()代替相关代码。

 
 

您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

<think>我们正在讨论对齐内存访问(unaligned memory access)的原理、影响及解决方案。结合用户提供的PowerPC示例和之前关于中断尾链的讨论,但注意当前问题焦点是内存对齐。 原理: 1. 内存对齐:计算机系统通常要求数据在内存中的地址是某个值(通常是数据大小的整数倍)的倍数。例如,4字节整型变量地址应是4的倍数。 2. 对齐访问:当数据存储在非对齐地址(如一个4字节整数存储在地址0x1003,而不是0x1000或0x1004)时,对该数据的访问称为对齐内存访问。 影响: 1. 性能下降:在支持对齐访问的硬件上(如PowerPC),访问可能被拆分成多个对齐访问,导致额外周期。例如,一个4字节对齐访问可能被拆成两个2字节访问,然后合并。 2. 异常终止:某些架构(如早期ARM)不支持对齐访问,尝试对齐访问会触发硬件异常(如SIGBUS),导致程序崩溃。 解决方案: 1. 编译器自动对齐:编译器通常会将变量对齐到合适的边界(如结构体填充)。 2. 手动数据对齐:编程时确保数据地址对齐,例如使用对齐属性(如GCC的`__attribute__((aligned(4)))`)。 3. 内存拷贝:如果必须处理对齐数据,可以先将数据拷贝到对齐内存区域再访问(如使用`memcpy`)。 4. 使用硬件支持:在支持对齐访问的处理器上,可以允许对齐访问但需注意性能影响。 结合用户提供的PowerPC示例: - PowerPC支持对齐的32位整数访问,但会有性能损失(较小)[^1]。 此外,在系统编程中,内存对齐还影响缓存行利用、原子操作等。 下面我们详细展开回答。 </think>### 对齐内存访问的原理、影响及解决方案 #### 一、基本原理 对齐内存访问(Unaligned Memory Access)指数据对象跨越多个对齐单元边界的访问。其核心原理包括: 1. **硬件对齐要求** 处理器通常要求$n$字节数据存储在$n$的整数倍地址(如4字节整数地址需满足$addr\ mod\ 4=0$)。违反此规则即对齐访问[^1]。 2. **访问过程分解** 当访问跨越边界的数据(如4字节int存储在地址0x03-0x06),硬件需执行: $$ \text{访问} = \text{读取低地址片段}(0x00-0x03) + \text{读取高地址片段}(0x04-0x07) + \text{数据重组} $$ 此过程需2次内存操作和移位合并操作[^1]。 3. **架构差异** - x86:硬件自动处理对齐访问(性能损失) - ARMv5/早期RISC:触发对齐错误异常 - PowerPC:支持32位对齐访问但需额外周期[^1] #### 二、主要影响 | 影响类型 | 具体表现 | |------------------|--------------------------------------------------------------------------| | **性能损失** | 访问周期增加:对齐访问需$T$周期时,对齐访问达$2T+1$周期(数据重组开销)[^1] | | **原子性破坏** | 多字节操作(如64位写)可能被拆分为多次总线事务,导致中间状态暴露 | | **异常风险** | 在严格对齐架构触发硬件异常(如ARM的Alignment Fault),程序崩溃 | | **缓存效率** | 跨缓存行访问导致两行同时加载,增加缓存污染概率 | #### 三、解决方案 1. **编译器辅助** ```c struct __attribute__((aligned(4))) Data { // GCC强制4字节对齐 int32_t x; char y; }; // 编译器自动填充字节避免对齐 ``` 2. **编程实践** - 指针转换时验证地址:`if((uintptr_t)ptr % sizeof(int) != 0) handle_error()` - 使用内存拷贝避免直接访问: ```c void read_unaligned(uint8_t* src) { uint32_t value; memcpy(&value, src, 4); // 安全读取对齐数据 } ``` 3. **硬件层面** - 现代处理器(如ARMv7+)引入硬件支持对齐访问 - 内存控制器优化:合并跨边界请求(如Intel的Data Bus Turnaround Elimination) 4. **数据结构优化** 调整元素顺序减少填充: ```c // 优化前:sizeof=12(因y后需3填充) struct Bad { char x; int32_t y; }; // 优化后:sizeof=8 struct Good { int32_t y; char x; // 无需填充 }; ``` #### 四、性能对比示例 $$ \begin{array}{c|c|c} \text{访问类型} & \text{ARM Cortex-M4周期} & \text{PowerPC e500周期} \\ \hline \text{对齐32位读} & 1 & 1 \\ \text{对齐32位读} & \text{异常} & 3 \\ \text{缓存行边界跨越} & 6 & 8 \\ \end{array} $$ > 注:对齐访问在严格对齐架构可能产生$100+$周期异常处理开销[^1] ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值