其实就是任务创建失败。
所有任务内存总和超过了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);