验证环境
-
NUCLEO-L476RG 开发板,板载 STM32L476RGT6(96K SARM1 + 32K SRAM2)
-
Win10 64 位
-
Keil MDK 5.36
-
RT-Thread 5.0.1 版本(2023-05-28 master 主线)
功能描述
-
最近在研究 RT-Thread 内存的管理,熟悉了一下 memheap 的功能实现,并且了解到, memheap 支持多块内存(物理地址不连续)的管理,当开启 memheap 后,rt_malloc 会遍历所有注册的 heap 内存块,并且进行 内存的申请与释放。
-
当前 STM32L476RGT6 支持两块 SRAM,其中 SRAM1 96KB,还有一块 SRAM2 32KB,SRAM2 默认没有使用,如何开启 SRAM2 呢?
开启 memheap
-
STM32L476RGT6 SRAM 总共:128KB,其中 SRAM1 默认开启, SRAM2 默认没有开启
-
首先 RT-Thread 开启 memheap
-
通过 RT-Thread ENV 工具: menuconfig,配置使能 memheap
-
当前测试的 BSP 为:
stm32l476-st-nucleo
-
这里注意,如果让 rt_malloc 自动在多个 Heap 内存池中申请,需要开启
RT_USING_MEMHEAP_AUTO_BINDING
,也就是 勾选[*] Use all of memheap objects as heap
-
配置使能 memheap 后,编译下载,通过 msh 命令
free
查看
msh >free
memheap pool size max used size available size
-------- ---------- ------------- --------------
heap 98304 7232 91072
- 发现 SRAM1 96KB 正常的初始化了
开启 SRAM2
- SRAM2 需要手动初始化,首先可以在
board.h
中增加 SRAM2 的内存信息:起始地址、大小
#define HEAP_SRAM2_BEGIN (0x10000000)
#define HEAP_SRAM2_SIZE (32 * 1024)
- 需要修改 board.c ,增加 SRAM2 的 memheap 的初始化操作
int system_sram2_init(void)
{
static struct rt_memheap memheap_sram2;
/* Heap initialization */
#if defined(RT_USING_HEAP)
rt_memheap_init(&memheap_sram2, "sram2", (void *)HEAP_SRAM2_BEGIN, (rt_size_t)HEAP_SRAM2_SIZE);
#endif
return 0;
}
INIT_BOARD_EXPORT(system_sram2_init);
- 这里使用 RT-Thread 自动初始化机制,初始化为 board 级别。
功能验证
-
RT-Thread ENV
scons --target=mdk5
,可以刷新 Keil MDK5 的工程 -
使用 Keil MDK5 打开工程,编译,下载到开发板,连接开发板串口,可以查看 SRAM2 正常初始化成功
memheap pool size max used size available size
-------- ---------- ------------- --------------
sram2 32768 48 32720
heap 98304 7232 91072
- 也就是
sram2
存在 memheap 的列表中了
内存申请
-
rt_malloc 底层由 memheap 实现后,并且使能
RT_USING_MEMHEAP_AUTO_BINDING
,使用 rt_malloc 会自动在所有 heap 中 操作 -
测试用例:内存申请与释放
#define MEMHEAP_BLOCK_NUM 64
static void *buf[MEMHEAP_BLOCK_NUM] = { 0 };
void memheap_alloc_test(void)
{
for (int i = 0; i < MEMHEAP_BLOCK_NUM; i++)
{
buf[i] = rt_malloc(3 * 1024 - 24);
if (!buf[i])
{
rt_kprintf("malloc failed, index = %d\n", i);
return;
}
}
}
MSH_CMD_EXPORT(memheap_alloc_test, memheap_alloc_test);
void memheap_free_test(void)
{
for (int i = 0; i < MEMHEAP_BLOCK_NUM; i++)
{
if (buf[i])
{
rt_memheap_free(buf[i]);
}
}
}
MSH_CMD_EXPORT(memheap_free_test, memheap_free_test);
- 测试结果
-
发现 rt_malloc 自动在 新增加的 sram2 中申请了内存
-
free 申请的内存,发现内存可用大小恢复了
专用 heap 内存
-
如果不使能
RT_USING_MEMHEAP_AUTO_BINDING
, 新注册的 memheapsram2
,不会被系统 rt_malloc 使用到,需要用户自己定义 内存申请与释放的函数进行 专用内存的管理 -
大概的管理思路如下:
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);
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(1024);
if (!user_ptr[i])
{
rt_kprintf("malloc failed, index = %d\n", i);
return;
}
}
}
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])
{
user_free(user_ptr[i]);
}
}
}
MSH_CMD_EXPORT(user_free_test, user_free_test);
- 这样
user_alloc
与user_free
只会操作指定的 memheap
- 【备注】如果同时开启了
RT_USING_MEMHEAP_AUTO_BINDING
,并且又自定义了某个 memheap的 内存申请与释放操作,rt_malloc 常规内存申请,依旧有可能 申请这个 特定的 memheap 的内存
小结
-
经过测试发现,一直申请某个大小的 memheap 内存并且不释放,会出现 hardfault 死机问题,后面抽时间研究一下死机的原因。
-
以下:每次申请 512 字节内存,62次左右的时候,死机了。
-
可以通过 RT-Thread memheap,把几块物理上地址不连续的内存管理起来,统一使用 rt_malloc 、rt_free 等 内存操作接口进行操作,也可以独立管理各个 memheap 内存块,不过需要用户自己实现相应的 内存申请与释放接口