OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 1732|回复: 1

rt-thread动态内存分配探究

[复制链接]

5

主题

20

帖子

0

精华

初级会员

Rank: 2

积分
77
金钱
77
注册时间
2019-6-19
在线时间
12 小时
发表于 2022-7-9 21:47:57 | 显示全部楼层 |阅读模式
本帖最后由 SighingWind 于 2022-7-9 22:26 编辑

这些天在学习STemWin,用的是原子的探索者F407,移植到rt-thread 3.1.3 nano下,跟着原子哥的例程进行学习。
到了后面字体和图像这块,用到了动态内存分配,记得rt-thread也有自己的内存管理函数,于是就仔细研究了一下,现把一些体会写出来,希望高手指正。

rt-thread的片内单块的SRAM的堆管理很简单,是在board.c文件中建立一个数组,把这个数组作为堆空间
#define RT_HEAP_SIZE 1024
static uint32_t rt_heap[RT_HEAP_SIZE];     // heap default size: 4K(1024 * 4)

而我看到rt-thread文档中提到了可以使用memheap方式把多个地址不连续的内存粘合起来作为一个堆进行使用,这个相当具有吸引力。但文档里的介绍很简单,只是一带而过,也没有例程。

根据文档的介绍,在rtconfig.h中加入以下两个开关
#define RT_USING_MEMHEAP
#define RT_USING_MEMHEAP_AS_HEAP

RT_USING_MEMHEAP是必须要定义的,定义之后,可以使用rt_memheap_init()函数,
函数原型:
rt_err_t rt_memheap_init(struct rt_memheap *memheap,
                         const char        *name,
                         void              *start_addr,
                         rt_size_t         size)

我在board.c中为每个堆定义一个静态全局struct rt_memheap变量,作为其参数之一。
static struct rt_memheap inner_heap;
static struct rt_memheap ex_heap;
static struct rt_memheap cmm_heap;

然后是名称,地址与大小,地址不可以与系统堆冲突之后进行初始化,返回值res并非必须,只是为了测试方便。
res = rt_memheap_init(&inner_heap, "IRAMHeap", (void*)(0x20000000 + 0x000052d0), 0x00020000 - 0x000052d0);
res = rt_memheap_init(&ex_heap, "ERAMHeap", (void*)(0x68000000 + 512*1024), 512*1024);
res = rt_memheap_init(&cmm_heap, "CMMHeap", (void*)(0x10000000 + 0x00002000), 0x00010000 - 0x00002000);

初始化的地址信息来自于MAP文件,作为测试,我从CMM区域定义了一个静态数组
(需要在设置里勾选IRAM2,不过如果不勾选,不会报错,而且不会对堆的初始化产生影响。只是MAP文件里不会出现相关的信息,而且我估计如果真要使用这个数组,可能就会报错)
static uint8_t CMM_Array[0x2000] __attribute__((at(0x10000000)));

相关MAP文件内容:
CMMRAM:定义了一个静态数组
  Execution Region RW_IRAM2 (Exec base: 0x10000000, Load base: 0x0804c7b0, Size: 0x00002000, Max: 0x00010000, ABSOLUTE)

    Exec Addr    Load Addr    Size         Type   Attr      Idx    E Section Name        Object
    0x10000000        -       0x00002000   Zero   RW         2640    .ARM.__AT_0x10000000  board.o

内部RAM:
    Execution Region RW_IRAM1 (Exec base: 0x20000000, Load base: 0x0804c2b8, Size: 0x000052d0, Max: 0x00020000, ABSOLUTE, COMPRESSED[0x000004f8])

外部RAM:为emWin分配了512K
  Load Region LR$$.ARM.__AT_0x68000000 (Base: 0x68000000, Size: 0x00000000, Max: 0x00080000, ABSOLUTE)

    Execution Region ER$$.ARM.__AT_0x68000000 (Exec base: 0x68000000, Load base: 0x68000000, Size: 0x00080000, Max: 0x00080000, ABSOLUTE, UNINIT)

    Exec Addr    Load Addr    Size         Type   Attr      Idx    E Section Name        Object

    0x68000000        -       0x00080000   Zero   RW         2753    .ARM.__AT_0x68000000  guiconf.o

这样之后就可以直接使用rt_malloc, rt_free进行内存的分配了,rt-thread自己动态建立的各种对象也会不受影响,在我的测试中,只保留了4K的默认堆空间,而分配的任务栈使用了10k,并没有问题。后来甚至在board.c有关系统堆的代码全部注释掉都没有问题。
//#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
//#define RT_HEAP_SIZE 1024
//static uint32_t rt_heap[RT_HEAP_SIZE];     // heap default size: 4K(1024 * 4)

//RT_WEAK void *rt_heap_begin_get(void)
//{
//    return rt_heap;
//}

//RT_WEAK void *rt_heap_end_get(void)
//{
//    return rt_heap + RT_HEAP_SIZE;
//}
//#endif
。。。
//#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
//    rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get());
//#endif

但是,如果只是只是定义了RT_USING_MEMHEAP,而不定义RT_USING_MEMHEAP_AS_HEAP,则无法使用统一的rt-malloc和rt-free,这两个函数只能用于rt_heap[RT_HEAP_SIZE]所定义的系统堆,而且rt_thread动态创建的各对象也只能在这上面创建。而各单独的memheap则必须使用rt_memheap_alloc(struct rt_memheap *heap, rt_size_t size),rt_memheap_free(void *ptr)等系列函数。

虽然可以统一使用rt_malloc进行分配,但并不意味这这些内存块真正连成了一块,能分配的最大内存块只是各组成内存块中最大的一块。另外,分配的优先顺序还没有探究,不过如果要在指定的内存块中进行分配,还是可以使用rt_memheap_alloc()等函数进行分配。
如果需要使用rt_memheap_alloc()等函数,显然,其用到的struct rt_memheap参数必须是全局的,而不是之前的静态的。

另外发现,rt_memheap_init函数并不检查地址的准确性,所以,地址的准确性必须自己来确定。

测试线程(基于rt-thread文档):
void mem_thread_entry(void* parameters)
{
        uint32_t i;
        char* ptr = RT_NULL;
        for (i = 0; ;i++)
        {
               
//              ptr = (void*)rt_malloc(1<<i);
                ptr = (void*)rt_memheap_alloc(&cmm_heap, 1<<i);
                if (ptr != RT_NULL)
                {
                        rt_kprintf("get memory: %d bytes\r\n", (1<<i));
//                     rt_free(ptr);
                        rt_memheap_free(ptr);
                        rt_kprintf("free memory: %d bytes\r\n", (1<<i));
                        ptr = RT_NULL;
                }
                else
                {
                        rt_kprintf("try to get %d bytes memory failed!\r\n", (1<<i));
                        return;
                }
        }
}

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

13

主题

644

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1873
金钱
1873
注册时间
2021-4-16
在线时间
477 小时
发表于 2022-7-11 11:17:28 | 显示全部楼层
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-5-15 08:07

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表