有没有想过什么移植FreeRTOS时,为什么有多种的内存文件,我们工程只使用Heap_4,其他的有什么用?每个的区别是什么?FreeRTOS是一种流行的实时操作系统,广泛应用于嵌入式系统开发中。在嵌入式系统中,内存管理是一个非常重要的问题,因为资源有限,必须合理地分配和使用内存。本文将介绍FreeRTOS中的内存管理机制,并给出一些通俗易懂的例子。
文章目录
- 1. 内存管理
- 1.1 静态创建任务
- 2. 内存管理文件
- 3. 动态内存管理
- 总结
系统移植的文章可以查看这个:
【FreeRTOS】FreeRTOS移植stm32详细步骤介绍
1. 内存管理
在FreeRTOS中,创建任务有两种方式:静态创建任务和动态创建任务。
1.1 静态创建任务
静态创建任务是在编译时为任务分配固定大小的内存块。通过定义任务时的参数来指定任务所需的栈空间大小。静态创建任务的函数是xTaskCreateStatic()
,示例如下:
TaskHandle_t xTaskCreateStatic(TaskFunction_t pxTaskCode,const char *pcName,const uint32_t ulStackDepth,void *pvParameters,StackType_t *puxStackBuffer,StaticTask_t *pxTaskBuffer
);
其中,pxTaskCode
是任务函数的指针,pcName
是任务的名称,ulStackDepth
是任务栈的大小,pvParameters
是传递给任务函数的参数,puxStackBuffer
是任务栈的起始地址,pxTaskBuffer
是任务控制块的起始地址。通过静态创建任务,可以在编译时为任务分配固定大小的内存块,避免了动态内存分配的开销和风险。
2. 内存管理文件
-
heap_1.c:这是最简单的内存管理实现,它使用静态数组作为堆内存,只能申请,不能释放,就是只实现了
malloc
功能,没有实现free
功能。实现的原理就是定义一个大数组,然后将合适的空间静态的分配给每个任务,如果某个任务或队列信号量等删除了,那么这个空间也没办法释放,所以它适用于只创建,不删除的系统中。 -
heap_2.c:这是对heap_1.c的改进,它支持动态内存分配和释放,但没有内存块合并的功能。跟Heap_1不一样的是,Heap_2使用最佳匹配算法来分配内存,并且支持了free功能,最佳匹配算法就是加入我要创建一个任务,它需要17字节的空间,算法可以在多个碎片空间内存中找出最佳的空间,例如有20、15、10、5字节的空间,算法就会分配20空间的内存中的17字节给系统使用,剩下的3字节仍然是空闲字节,可以被申请,但是如果一直没有被申请,就形成了内存碎片,所以Heap_2会产生内存碎片。适用于需要动态内存管理的应用场景,但不需要内存块合并的场景。
-
heap_3.c:这是对heap_2.c的改进,它支持动态内存分配和释放,并且实现了内存块合并的功能。适用于需要动态内存管理的应用场景,且需要内存块合并的场景。
-
heap_4.c:这是对heap_3.c的改进,它支持动态内存分配和释放,并且实现了内存块合并和分割的功能。Heap_4使用首次适应算法来分配内存,还会将相邻的空闲内存合并成为一个更大的空闲内存,这有助于较少内存的碎片问题,当需要分配一块内存时,FreeRTOS会遍历空闲内存块链表,查找第一个大小大于等于所需内存的空闲内存块。如果找到了满足条件的空闲内存块,FreeRTOS会将其分割成两部分,一部分用于分配,另一部分保留为剩余的空闲内存块。如果没有找到满足条件的空闲内存块,FreeRTOS会根据需要进行堆内存扩展,以满足分配要求。分配完成后,FreeRTOS会返回分配的内存块的起始地址。。适用于需要动态内存管理的应用场景,且需要内存块合并和分割的场景。
-
heap_5.c:这是最复杂的内存管理实现,它支持动态内存分配和释放,并且实现了内存块合并、分割和按需增减堆内存的功能。适用于需要灵活管理堆内存的应用场景,但需要更多的内存管理开销。
我们很多情况下都是使用Heap_4,有多块内存会使用Heap_5,其他的很少用到。
3. 动态内存管理
动态内存管理是指在运行时根据需要动态分配内存。在FreeRTOS中,可以使用内置的内存管理器来实现动态内存分配。内存管理器提供了两个函数:pvPortMalloc
和vPortFree
,分别用于分配和释放内存。
例如,下面是一个动态分配内存的示例:
#include "FreeRTOS.h"
#include "task.h"void vTaskFunction(void *pvParameters) {char *pcBuffer = pvPortMalloc(1024);if (pcBuffer != NULL) {// 使用内存}vPortFree(pcBuffer);
}int main() {xTaskCreate(vTaskFunction, "Task", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);vTaskStartScheduler();return 0;
}
在任务函数中,使用pvPortMalloc
函数分配了一个大小为1024字节的内存块,并将其赋值给pcBuffer
指针。如果分配成功,就可以使用该内存块。最后,使用vPortFree
函数释放内存块。
总结
FreeRTOS提供了静态内存管理和动态内存管理两种方式,可以根据具体情况选择合适的方式。静态内存管理可以避免动态内存分配的开销和风险,但需要在编译时为任务分配固定大小的内存块。动态内存管理可以根据需要动态分配内存,但可能存在内存碎片和分配失败的风险。在实际开发中,应该根据具体情况选择合适的内存管理方式。