FreeRTOS内存管理简介
在使用 FreeRTOS 创建任务、队列、信号量等对象的时候, FreeRTOS 一般都提供了两种方法,
- 动态方法创建:自动地从 FreeRTOS 管理的内存堆中申请所创建对象所需的内存,在对象被删除后,又可以将这块内存释放会 FreeRTOS 管理的内存堆。
- 静态方法创建:需要用户提供各种内存空间,并且使用静态方式占用的内存空间一般固定下来了,即使任务、队列等被删除后,这些被占用的内存空间也没有其他用途。
备注 :动态方式管理比静态方式更加灵活。
标准的 C 库也提供了函数 malloc()和函数 free()来实现动态地申请和释放内存,但是标准 C 库的动态内存管理方法有如下几个缺点,
- 占用大量的代码空间,不适合用在资源紧缺的嵌入式系统
- 没有线程安全的相关机制。
- 具有不确定性,体现在每次执行的时间不同。
- 内存碎片化
FreeRTOS内存管理算法
FreeRTOS提供了5种动态内存管理算法,分别为heap_1、heap_2、heap_3、heap_4和heap_5,这 5 种动态内存管理算法各自的特点如下所示:
- heap_1: 最简单,只允许申请内存,不允许释放内存。
- heap_2: 允许申请和释放内存,但不能合并相邻的空闲内存块。
- heap_3: 简单封装 C 库的函数 malloc()和函数 free(), 以确保线程安全。
- heap_4: 允许申请和释放内存,并且能够合并相邻的空闲内存块,减少内存碎片的产生。
- heap_5: 能够管理多个非连续内存区域的 heap_4。
heap_1内存管理算法
heap_1只实现了pvPortMalloc,没有实现vPortFree,只能申请内存,无法释放。
如果工程创建好的任务、队列、信号量等都不需要被删除,可以使用heap_1。
heap_1 内存管理算法管理的内存堆是一个数组,在申请内存的时候, heap_1 内存管理算法只是简单地从数组中分出合适大小的内存。
heap_1内存管理算法分配过程如下,
可以看到heap_1内存管理算法就像切蛋糕,切掉了就没有了。
heap_2内存管理算法
- 相比于 heap_1 内存管理算法, heap_2 内存管理算法使用了最适应算法,以支持释放先前申请的内存。
- heap_2 内存管理算法并不能将相邻的空闲内存块合并成一个大的空闲内存块,因此 heap_2 内存管理算法不可避免地会产生内存碎片。
最适应算法:就是将空闲内存按照内存块大小排序,当你申请一个内存时,找到最小的,可以满足所申请的内存大小的的内存块,并将这个内存块分配出去,分配出去的内存块剩余大小任然是空闲状态。
内存碎片:内存碎片是由于多次申请和释放内存,但释放的内存无法与相邻的空闲内存合并而产生的。
heap_2内存管理算法分配过程如下,
heap_2适用于频繁的创建和删除任务,且所创建的任务堆栈都相同的场景。
heap_3内存管理算法
heap_3内存管理算法就是封装了C库的malloc和free函数,建议自行学习。
heap_4内存管理算法
heap_4 内存管理算法使用了首次适应算法,也支持内存的申请与释放,并且 heap_4 内存管理算法还能够将空闲且相邻的内存进行合并,从而减少内存碎片的现象。
首次适用算法:就是将空闲内存块按照地址由高到低进行排序,当你要申请一块内存时,先是根据地址由高到低找到可以满足所需内存的内存块,然后也是一样,内存块多余的内存仍然是空闲状态。
heap_4内存管理算法分配过程如下,
heap_4适用于频繁的分配,释放不同大小的内存的场景。
heap_5内存管理算法
heap_5 内存管理算法是在 heap_4 内存管理算法的基础上实现的,因为 heap_5 内存管理算法使用与 heap_4 内存管理算法相同的内存分配、释放和合并算法,但是 heap_5 内存管理算法在 heap_4 内存管理算法的基础上实现了管理多个非连续内存区域的能力。
heap_5内存管理算法默认并没有定义内存堆 ,需要用户手动调用函数进行分配,heap_5 内存管理算法定义了一个结构体,用于表示内存区域的信息
typedef struct HeapRegion
{uint8_t * pucStartAddress; /* 内存区域的起始地址 */size_t xSizeInBytes; /* 内存区域的大小,单位:字节 */
} HeapRegion_t;
当我们要指定多块不连续的内存时,可以向如下一样指定,
const HeapRegion_t xHeapRegions[] =
{{(uint8_t *)0x80000000, 0x10000}, /* 内存区域 1 */{(uint8_t *)0x90000000, 0xA0000}, /* 内存区域 2 */{NULL, 0} /* 数组终止标志 */
};
vPortDefineHeapRegions(xHeapRegions);
heap_5适用于嵌入式系统中内存地址不连续的场景下使用。
内存管理函数
由于内存管理函数比较简单,下面介绍三个有关FreeRTOS内存管理的函数,
void* pvPortMalloc(size_t xWantedSize)
xWantedSize:申请的内存大小,以字节为单位
返回值:返回一个指针,指向以分配大小的内存,申请失败则返回NULL
void vPortFree(void* pv)
*pv:指针指向一个要释放的内存
size_t xPortGetFreeHeapSize(void)
返回值:返回当前剩余的空闲内存大小
备注:在一段内存没有被释放之前绝对不能在调用依次函数pvPortMalloc()为其再次分配内存,否则会导致内存泄漏。