在Freertos创建任务、信号量、队列等对象的时候,一般提供两种从创建方法,一是动态创建,二是静态创建,相比于静态创建,动态创建是Freertos从自己管理管理得内存中进行分配,在删除任务得时候,又可以释放之前创建得内存堆,比静态创建任务灵活许多。
除了Freertos中管理的内存算法,也可以使用C库提供的malloc()和free()来实现动态创建管理内存,但存在一下缺点:
1.会占用大量的代码空间
2.具有不确定性,表现为每次执行的时间不同
3.没有线程安全得相关机制
Freertos中提供了5中内存管理算法,分别是heap_1.c、heap_2.c、heap_3.c、heap_4.c、heap_5.c,这5种分别具有一下特点:
heap_1:只允许申请内存,不允许释放内存(适用于 个别嵌入式系统,一旦创建好就不会删除的任务)
heap_2:允许申请释放内存,但不能合并相邻空闲的内存块(会产生大量的内存碎片)
heap_3:简单封装了C库的malloc()、free()函数,确保线程安全
heap_4:允许申请和释放内存,并且可以合并相邻的内存块,减少内存碎片的产生(常用的内存管理算法)
heap_5:相当于可以管理多个非连续区域的heap_4(感觉像是heap_4的升级版);
相关的内存管理函数:
pvPortMalloc(pv):pv:所要申请的内存的大小,并返回内存的首地址
vPortFree(pv):pv:需要删除内存的首地址
xPortGetFreeHeapSize():获取申请内存的大小。
简单的实验:
/**
* @brief FreeRTOS例程入口函数
* @param 无
* @retval 无
*/
void freertos_demo(void)
{
xTaskCreate((TaskFunction_t )start_task, /* 任务函数 */
(const char* )"start_task", /* 任务名称 */
(uint16_t )START_STK_SIZE, /* 任务堆栈大小 */
(void* )NULL, /* 传入给任务函数的参数 */
(UBaseType_t )START_TASK_PRIO, /* 任务优先级 */
(TaskHandle_t* )&StartTask_Handler); /* 任务句柄 */
vTaskStartScheduler();
}
/**
* @brief start_task
* @param pvParameters : 传入参数(未用到)
* @retval 无
*/
void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); /* 进入临界区 */
/* 创建任务1 */
xTaskCreate((TaskFunction_t )task1,
(const char* )"task1",
(uint16_t )TASK1_STK_SIZE,
(void* )NULL,
(UBaseType_t )TASK1_PRIO,
(TaskHandle_t* )&Task1Task_Handler);
vTaskDelete(StartTask_Handler); /* 删除开始任务 */
taskEXIT_CRITICAL(); /* 退出临界区 */
}
/**
* @brief task1
* @param pvParameters : 传入参数(未用到)
* @retval 无
*/
void task1(void *pvParameters)
{
while(1)
{
uint8_t key = 0;
uint8_t *buf = NULL;
size_t free_size = 0;
while (1)
{
key = key_scan(0);
switch (key)
{
case KEY0_PRES:
{
buf = pvPortMalloc(30); /* 申请内存 */
break;
}
case KEY1_PRES:
{
if (NULL != buf)
{
vPortFree(buf);
buf = NULL;
}
break;
}
default:
break;
}
printf("总内存大小%d\r\n" ,configTOTAL_HEAP_SIZE);
free_size = xPortGetFreeHeapSize();
printf("剩余内存大小%d\r\n" , free_size);
}
}
}