C库函数与FreeRTOS内存管理区别
在C语言的库函数中,有mallc、free等函数可以申请以及释放内存空间,那么这为什么不适用于FreeRTOS的内存管理呢?
- 不适合用在资源紧缺的嵌入式系统中
- 这些函数的实现过于复杂、占据的代码空间太大
- 并非线程安全的(thread-safe)
- 运行有不确定性:每次调用这些函数时花费的时间可能都不相同
- 内存碎片化
- 使用不同的编译器时,需要进行复杂的配置
- 有时候难以调试
FreeRTOS内存管理
FreeRTOS内存管理方式主要依靠堆和栈来实现
- 堆,heap,就是一块空闲的内存,需要提供管理函数
- malloc:从堆里划出一块空间给程序使用
- free:用完后,再把它标记为"空闲"的,可以再次使用
- 栈,stack,函数调用时局部变量保存在栈中,当前程序的环境也是保存在栈中
- 可以从堆中分配一块空间用作栈
- 可以从堆中分配一块空间用作栈
FreeRTOS内存管理方法比较
Heap_1
它只实现了pvPortMalloc,没有实现vPortFree。
如果你的程序不需要删除内核对象,那么可以使用heap_1
⚫ 实现最简单,在定义好的一个大数组中分配内存
⚫ 没有碎片问题
⚫ 一些要求非常严格的系统里,不允许使用动态内存,就可以使用heap_1
Heap_2
Heap_2之所以还保留,只是为了兼容以前的代码。新设计中不再推荐使用Heap_2。建议使用Heap_4来替代Heap_2,更加高效。 Heap_2也是在数组上分配内存,跟Heap_1不一样的地方在于:
⚫ Heap_2使用最佳匹配算法(best fit)来分配内存
⚫ 它支持vPortFree
⚫最佳匹配算法: 假设heap有3块空闲内存:5字节、25字节、100字节。pvPortMalloc 想申请20字节,找出最小的、能满足pvPortMalloc的内存:25字节 把它划分为20字节、5字节。返回这20字节的地址,剩下的5字节仍然是空闲状态,留给后续的pvPortMalloc使用 。
缺点:
Heap_3
Heap_4
跟Heap_1、Heap_2一样,Heap_4也是使用大数组来分配内存。 Heap_4使用首次适应算法(first
fit)来分配内存。它还会把相邻的空闲内存合并为一个更大的空闲内存,这有助于较少内存的碎片问题。
首次适应算法:
⚫ 假设堆中有3块空闲内存:5字节、200字节、100字节
⚫ pvPortMalloc 想申请20字节
⚫ 找出第1个能满足pvPortMalloc的内存:200字节
⚫ 把它划分为20字节、180字节
⚫ 返回这20字节的地址
⚫ 剩下的180字节仍然是空闲状态,留给后续的pvPortMalloc使用
Heap_5
Heap_5 分配内存、释放内存的算法跟Heap_4是一样的。 相比于Heap_4,Heap_5并不局限于管理一个大数组:它可以管理多块、分隔开的内存。 在嵌入式系统中,内存的地址可能并不连续,这种场景下可以使用Heap_5。既然内存时分隔开的,那么就需要进行初始化:确定这些内存块在哪、多大。
指定内存方法,使用结构体。
typedef struct HeapRegion
{
uint8_t * pucStartAddress; // 起始地址
size_t xSizeInBytes; // 大小
} HeapRegion_t;
指定多块内存方法
HeapRegion_t xHeapRegions[] =
{
{ ( uint8_t * ) 0x80000000UL, 0x10000 }, // 起始地址0x80000000,大小0x10000
{ ( uint8_t * ) 0x90000000UL, 0xa0000 }, // 起始地址0x90000000,大小0xa0000
{ NULL, 0 } // 表示数组结束
};
初始化内存
void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions );