其实就是任务创建失败。
所有任务内存总和超过了FreeRTOSConfig.h的configTOTAL_HEAP_SIZE。
FreeRTOS内存管理
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
,在FreeRTOS.g中也有定义,为StaticTask_t
。
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 字节 |
堆栈大小
s
t
a
c
k
=
S
t
a
c
k
D
e
p
t
h
∗
s
i
z
e
o
f
(
S
t
a
c
k
T
y
p
e
t
)
stack = StackDepth * sizeof(StackType_t)
stack=StackDepth∗sizeof(StackTypet)
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
(84 + 200 * 4) * 2 + (84 + 256 * 4) = 2858 < 3072
(84+200∗4)∗2+(84+256∗4)=2858<3072
(
4
+
256
∗
4
)
∗
3
=
3291
>
3072
(4 + 256 * 4) * 3 = 3291 > 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);