关于FreeRTOS中堆栈的一些思考
裸机时的堆栈问题
内存被分为许多区域,其中包含堆和栈,当然还有其他一些区域,见内存各区域区别。
-
内存栈中存储的是函数调用的形参、非静态局部变量以及函数调用信息。栈由编译器自动进行管理,无需人为干预。如果函数的局部变量定义大小过大(比如定义在函数内部定义超大型数组等),超过了链接脚本定义的栈区大小将会发生溢出,程序将会崩溃!
-
内存堆是用于动态内存分配的,由编程人员手动进行管理。
使用malloc函数手动申请内存和使用free手动释放,申请的内存在使用结束之后没有得到释放将会产生内存泄漏,导致程序崩溃!
当使用malloc申请的内存大于堆剩余的容量时,将会导致申请失败!
以stm32为例,在在启动文件中可以定义栈和堆空间的大小,一般堆和栈默认都为0x200,如下所示。
为了满足项目需求,可以按需对堆和栈空间进行调整。当然,调整的大小不能超过内存总容量(😄)!
运行FreeRTOS时的堆栈问题
FreeRTOS每个任务在创建时都会分配一个任务栈,任务的非静态局部变量等都会存储在任务创建分配时的任务栈中,而非系统栈(也就是前面裸机中提到的栈区)中,而只有中断函数和中断嵌套使用系统栈。1
任务栈的总容量是在FreeRTOSConfig.h
文件中定义的,或者说任务栈是从这个HEAP中分配的。我们使用pvPortMalloc
函数申请内存时,也是从这个HEAP中申请的。
#define configTOTAL_HEAP_SIZE ((size_t)8192)
那这个HEAP的来源呢?FreeRTOS使用一个静态数组作为HEAP,以我使用的heap_4.c
内存管理策略来说,它定义在heap_4.c
这个文件里面。因为这个HEAP来自于静态数组,所以它存在于数据段(具体为.bss段),并不是我一开始认为的FreeRTOS所使用的HEAP来自于系统的堆。
static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
在启动文件配置的Heap_Size EQU 0x200
和FreeRTOS中的HEAP并无关系,启动文件中配置的Heap_size
必须比configTOTAL_HEAP_SIZE
大是没有依据的。
C库的malloc函数在微控制器并不是线程安全的。所以,为了线程安全,在使用FreeRTOS时进行动态内存申请时,请使用FreeRTOS提供的pvPortMalloc
和vPortFree
函数。
这里仅为自己的一些思考,如有错误,请大家指正!