memheap死机问题的分析与解决

验证环境
nucleo-l476rg 开发板,板载 stm32l476rgt6(96k sarm1 + 32k sram2)
win10 64 位
keil mdk 5.36
rt-thread 5.0.1 版本(2023-05-28 master 主线)
bsp : bsp\\stm32\\stm32l476-st-nucleo
功能描述
最近在研究 rt-thread 内存的管理,熟悉了一下 memheap 的功能实现,并且了解到 memheap 支持多块内存(物理地址不连续)的管理,当开启 memheap 后,rt_malloc 可以遍历所有注册过的 memheap 内存块,并且进行 内存的申请与释放。
当前 stm32l476rgt6 支持两块 sram,其中 sram1 96kb,还有一块 sram2 32kb,sram2 默认没有使用,尝试开启 sram2
环境搭建
stm32l476-st-nucleo 开启 memheap 的方法
stm32l476-st-nucleo 开启 sram2 的方法
#define heap_sram2_begin (0x10000000)
#define heap_sram2_size (32 * 1024)
static struct rt_memheap memheap_sram2;
int system_sram2_init(void)
{
return rt_memheap_init(&memheap_sram2, sram2, (void *)heap_sram2_begin, (rt_size_t)heap_sram2_size);
}
init_board_export(system_sram2_init);
功能测试
写两个测试命令:一直申请内存直到无法申请内存,一直释放所以申请的内存,确认 rt_malloc 会自动到新增加的 memheap sram2 中申请内存
功能验证通过,但是遇到死机问题
测试的函数
void *user_alloc(rt_size_t size)
{
return rt_memheap_alloc(&memheap_sram2, size);
}
void user_free(void *ptr)
{
rt_memheap_free(ptr);
}
void user_alloc_test(void)
{
for (int i = 0; i < memheap_block_num; i++)
{
user_ptr[i] = user_alloc(500);
if (!user_ptr[i])
{
rt_kprintf(malloc failed, index = %d\\n, i);
return;
}
else
{
rt_kprintf([%d] : 0x%08x\\n, i, user_ptr[i]);
}
}
}
msh_cmd_export(user_alloc_test, user_alloc_test);
void user_free_test(void)
{
for (int i = 0; i < memheap_block_num; i++)
{
if (user_ptr[i])
{
rt_kprintf([%d] : 0x%08x\\n, i, user_ptr[i]);
user_free(user_ptr[i]);
}
}
}
msh_cmd_export(user_free_test, user_free_test);
死机的信息
死机后,打印线程,发现 idle 线程栈异常
开启 cmbacktrace 组件后,发现死机的问题不是固定的,申请申请一个小内存,都会触发异常
问题分析
idle 线程的结构数据被破坏了,这就说明,内存越界了,但是测试例程只调用了 rt-thread memheap 的 内存申请与释放 api,并没有其他的操作
手动申请一块内存,没有触发死机, list thread 发现,idle 线程的栈数据,依旧是异常的!
由于 开发板可以 单步调试,所以经过单步调试,加上分析,确认内存的范围,各个线程栈的内存范围,发现了一个奇怪的问题: 申请的内存偶尔会与线程栈的【静态内存】重叠
由于死机问题并不是必现,但是 idle 线程栈数据异常是必现的。当前怀疑 memheap 的内存范围设置存在问题,通过对比其他开发板的 bsp,发现了问题所在。
原来 bsp stm32l476-st-nucleo 系统的内存 heap_begin 设置有问题,直接设置的 第一块内存的起始地址:
#define stm32_sram1_start (0x20000000)
#define heap_begin stm32_sram1_start
初步看上去好像没有问题,其实rt-thread 开机后,静态的内存数据、线程栈,依旧会占用一些内存,也就是其实内存地址,不能设置为 stm32_sram1_start,而是 【剩余内存】
【剩余内存】或者叫【空闲内存】的获取方法如下:
#if defined(__armcc_version)
extern int image$$
rw_iram1
zi
limit;
#define heap_begin ((void *)&image
rw_iram1
zi
limit)
#elif iccarm
#pragma section=cstack
#define heap_begin (__segment_end(cstack))
#else
extern int __bss_end;
#define heap_begin ((void *)&__bss_end)
#endif
如在 keil mdk5 上,是 #define heap_begin ((void *)&image
rw_iram1
zi$$limit), 也就是 sram1 的 剩余内存作为系统 堆内存使用,而不是 sram1 的全部内存作为 堆内存使用
解决方法
如上,重新设置 heap_begin 即可
编译发现 rw_iram1 不存在,需要修改链接文件:bsp\\stm32\\stm32l476-st-nucleo\\board\\linker_scripts\\link.sct,增加 rw_iram1 的定义
rw_iram1 0x20000000 0x00018000 { ; rw data
.any (+rw +zi)
}
以上修改后,memheap 内存测试通过,不再触发死机
小结
memheap 使用起来还是比较的简单,可以通过设置 开启 rt_using_memheap_auto_binding,也就是 勾选 [*] use all of memheap objects as heap,决定新增加的 memheap 的内存是否参与系统常规的内存管理,如 rt_malloc、rt_free
用户可以单独的实现自己的 memheap 内存块 alloc、free 函数,这样只操作特定的 memheap。
当前的一个小缺点:如果 memheap 内存块较多,超过2个,如 ram1、ram2、ram3,并且开启了 [*] use all of memheap objects as heap,想实现 ram1与 ram2 作为系统通用内存管理,ram3 用户专用内存管理,那么当前的 memheap 机制做不到,因为 rt_malloc 依旧会在 ram1、ram2 不能申请内存时,去 ram3 申请内存。

模拟混合信号IC厂商Exar全球大幅裁员约40%
罗姆获选为UAES的SiC功率解决方案优先型供应商
Vishay新型红外发射器辐照强度提高了30%
变相降价 小米手机官翻版仅售1599元
科创板上会遇坎 晶丰明源表态继续“赶路”
memheap死机问题的分析与解决
ossutil上传性能调优
商场室内LED显示屏的作用_商场室内LED显示屏的优势
即付即用存储使用模式及其挑战
CA70型无极性固体电解质钽电容器
物联网网关的关键技术和应用方向的详细分析
基于STM32和μC/OS-Ⅱ的热力站监控系统设计
柔性制造和智慧物流解决方案供应商宾通智能完成6000万元A轮融资
转转的2019:脚踏实地比仰望星空更重要
如何使用Keil创建STM32F103的工程
在SUV界中,哈弗H6霸占着销售榜首,传祺GS4冲刺至亚军,长安蓄势待发!
各类有源晶振选型攻略,果断收藏!
世界智能水下机器人挑战赛在天津滨海高新区技术产业开发区渤龙山庄举办
嵌入式DDR总线结构介绍及硬件信号布线分析
光伏逆变器工作原理与光伏逆变器相关元件推荐