内存管理
- freertos支持动态分配内存和静态分配内存
- Freertos的内存分配是在portable层中实现,与内核实现分开。目录:Source/Portable/MemMang
静态内存管理
特点
- 对象可以分配在特定的内存地址处;
- 最大内存占用可以在链接时确定,而不是运行时;
- 用户不需要关心内存分配失败的处理方式;
- 允许在不使用动态内存分配的地方使用RTOS。
定义宏 configSUPPORT_STATIC_ALLOCATION = 1
使用静态内存分配。既可以使用以下函数,里面使用的内存分配是静态内存分配方式。
动态内存管理
大多数使用freertos的场合,还是使用的动态内存分配。freertos提供了五种动态内存分配方法。如第一张图所示。
动态分配RTOS对象的特点:
- 最大可能减少系统使用的最大RAM;
- 当创建object时需要更少的函数参数;
- 内存再RTOS的API函数函数中自动分配;
- 应用程序不需要关心内存分配本身;
- RTOS内存分配API函数,会返回heap的使用信息,使得用户可以优化heap的使用;
- 内存分配的方法有多种方式,可以适应于不同的应用场合。
内核对象内存分配,分配的内存来自:special freertos heap。即ucHeap[ configTOTAL_HEAP_SIZE ]
也就是说,freertos运行起来后,里面动态分配的内存都是在ucheap
中分配。栈也是从ucheap
分配的 。
五种动态内存分配方法
- Heap1:适用于一旦创建好,就不需要删除的应用。(区别于静态分配)(自从freertos支持静态内存分配后,heap1分配方法很少被使用)
- Heap2:分配内存采用best fit算法;内存可以释放,但是不会被合并。
- Heap3:封装C标准的malloc函数和free函数,实现线程安全。使用条件:需要linker建立堆,编译器库实现malloc和free;不是确定性的;会增加RTOS内核的体积。
- Heap4:分配内存采用first fit策略(即选择第一个满足分配要求的内存块),释放内存后,相邻内存会被合并。所有内存块被按照地址从低到高保存在链表中,相邻内存块如果地址连续,则可以合并。
- Heap5:分配和释放策略类似于heap4。heap5同时允许使用多个非连续的内存区块作为系统的内存。
使用vPortDefineHeapRegions()函数初始化;创建任何对象都会调用pvPortMalloc(0函数,在此之前必须调用vPortDefineHeapRegions()函数初始化初始化。vPortDefineHeapRegions()函数参数是一个HeapRegion结构体的数组,
const HeapRegion_t xHeapRegions[] =
{
{ ( uint8_t * ) 0x80000000UL, 0x10000 },
{ ( uint8_t * ) 0x90000000UL, 0xa0000 },
{ NULL, 0 } /* Terminates the array. */
};//各地址片段必须按顺序放置在数组中
Freertos操作系统是个大程序,那么这个程序运行过程中需要堆和栈。堆用于保存TCB或者队列、信号量等内核结构变量。栈用于保存每个任务的运行环境和过程变量or局部变量。于是在freertos编译的时候,定义了一个大的数组,ucHeap[ configTOTAL_HEAP_SIZE ]。
整个ucheap是一个大数组,heap本来是堆的意思,但是这里可以说是堆,也可以说不是,自己灵活变通理解。每个任务函数需要用到的栈从这个heap中分配;内核控制变量:TCB和队列、信号量等也从heap中分配,都是使用pvPortMalloc()函数。
The xPortGetFreeHeapSize()可以返回剩余的heap空间大小;但是不能提供碎片信息。
参考资料
《Mastering the FreeRTOS™ Real Time Kernel》
《cortex M3 权威指南》
《freertos 开发手册》
freertos
公众号:嵌入式软件和硬件