FreeRTOS内存管理:创建了三个任务,但是发现有一个任务没有运行

其实就是任务创建失败。

所有任务内存总和超过了FreeRTOSConfig.h的configTOTAL_HEAP_SIZE。

FreeRTOS内存管理

[中字] RTOS入门 Part 4 - 内存分配

stack(栈)、heap(堆)、static

了解stack(栈)、heap(堆)、static

任务内存组成

任务被创建时,会在heap占用一块空间存放,这段内存会被分为TCB(任务控制块)+STACK1(任务专属栈空间)。

TCB

STACK

结构体

调用vTaskCreate产生的,告诉CPU需要分配多少heap来存放task stack

任务函数、任务地址、任务优先级……

当任务要被切换时,存放当前任务的状态

不同任务创建时内存位置

task heap管理策略

动态分配内存时,程序会试图寻找最大的连续堆空间提供给你,但当你不停地分配和释放堆空间,可能会导致堆空间碎片化,(尽管还有剩下一些可用的碎片堆空间),因此FreeRTOS就提供了一些堆管理策略。

heap_1:不允许释放堆空间,使堆的一部分变成静态内存

heap_2:过时

heap_3:封装了malloc和free,使它们变得线程安全

heap_4:推荐使用,可以合并化碎片堆空间。

heap_5:最高级的,能联合使用不连续的堆空间

ps:C的malloc和free都是不安全的,它们所需运行时间编译时无法确定。

计算任务所占内存

TCB

通常定义在task.c中,结构体命名为tskTCB

* * * * *

printf("TCB Size: %d bytes\n", (int)sizeof(StaticTask_t));//可以发现,tskTAB后面被多次define套壳

配置项

对 TCB 大小的影响

configUSE_TRACE_FACILITY=1

增加调试字段,TCB 增大 20~50 字节

configUSE_TASK_NOTIFICATIONS=0

移除通知字段,TCB 减小约 8 字节

configUSE_APPLICATION_TASK_TAG=1

增加标签字段,TCB 增大 4 字节

堆栈大小

\(stack = StackDepth * sizeof(StackType_t)\)

StackDepth:创建任务时指定的堆栈深度(如 xTaskCreate(..., 256, ...) 中的 256)。

StackType_t:通常为 uint32_t(4 字节),因此 256 字的堆栈占用 256 * 4 = 1024 字节。

printf("TCB Size: %d bytes\n", (int)sizeof(StackType_t));//可以发现,tskTAB后面被多次define套壳

监控内存是否超限

// 示例:3 个任务的总内存需求

uint32_t total_memory = 3 * (sizeof(StaticTask_t) + (256 * sizeof(StackType_t)));

if (total_memory > configTOTAL_HEAP_SIZE) {

printf("内存不足!需增大堆或减少任务堆栈!");

}

运行时监控堆内存

void check_memory() {

printf("剩余堆内存: %d 字节\n", xPortGetFreeHeapSize());

}

检测堆栈使用率

void task_function(void *pvParameters) {

UBaseType_t high_watermark;

while(1) {

high_watermark = uxTaskGetStackHighWaterMark(NULL);

printf("堆栈剩余: %d 字\n", high_watermark);

osDelay(1000);

}

}

本次程序存在的问题:任务创建失败

任务分配的堆栈超出FreeRTOSConfig.h的configTOTAL_HEAP_SIZE

#define configTOTAL_HEAP_SIZE ((size_t)3072)

当前程序计算得到:

\((84 + 200 * 4) * 2 + (84 + 256 * 4) = 2858 < 3072\)

\((4 + 256 * 4) * 3 = 3291 > 3072\)

导致第三个任务创建失败。

即只需要修改:

osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 200);

//osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 256);

defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);

/* definition and creation of myTask02 */

osThreadDef(myTask02, StartTask02, osPriorityNormal, 0, 200);

//osThreadDef(defaultTask, StartTask02, osPriorityNormal, 0, 256);

myTask02Handle = osThreadCreate(osThread(myTask02), NULL);

/* definition and creation of myTask03 */

osThreadDef(myTask03, StartTask03, osPriorityNormal, 0, 256);

myTask03Handle = osThreadCreate(osThread(myTask03), NULL);

Back to top: