目录
一、什么是堆
堆(Heap)是一种动态分配的内存方式,用于存储程序运行时动态创建的对象或数据。
堆由程序员手动分配和释放的,分配速度相对较慢,但大小理论上没有限制。
堆的管理通常由操作系统或编译器提供的库函数来完成,如使用malloc函数分配内存,使用free函数释放内存。
堆上的数据可以通过指针进行访问,且由于堆的管理需要额外的开销,所以堆的操作相对较慢。
二、什么是栈
栈(Stack)是一种后进先出(LIFO)的数据结构,主要存储函数的局部变量、函数参数以及函数返回地址等信息。
栈是由编译器自动分配和释放的,它的分配速度快,但大小有限,由编译器在编译时确定。
当函数被调用时,其局部变量和参数会被分配到栈上,并在函数返回时自动释放。栈的操作非常高效,因为它只需要移动栈指针即可。
栈上的数据是按着先进后出的顺序进行存储和访问的,且栈的大小是固定的。
三、STM32中堆栈的设置
此处以stm32f429的跑马灯项目为例,打开startup_stm32f429xx.s文件,有一段汇编代码是分配堆栈大小的,其中,Stack_Size为1024字节(0x400),这个就是栈的大小,Heap_Size为512字节(0x200),这就是堆的大小。
3.1堆的大小设置
堆的话如果我们没用到标准库的malloc,这个设置就没有用处,用默认的0x200即可,我们一般不会直接使用malloc去申请空间,因为这样会产生碎片浪费大量空间。
使用操作系统的时候,系统会开辟自己的堆空间,和stm32内存结构的堆空间是两码事,它们的大小没有关联,下图为freertos配置文件FreeRTosConfig.h分配的堆空间为46KB,远大于stm32的启动文件中配置的堆。
下面以freertos为例,将startup_stm32f429xx.s文件中配置的Heap_Size称为STM32内存结构中的堆,对比两种堆的不同。
-
用途:
- STM32内存结构中的堆:这是STM32微控制器提供的标准C库堆,主要用于用户程序中的动态内存分配。例如,当你使用malloc、calloc、realloc等C库函数时,就会从这个堆中分配内存。
- FreeRTOS堆:这是FreeRTOS实时操作系统(RTOS)为任务提供的动态内存管理机制。每个FreeRTOS任务都可以有自己的堆,用于存储任务在运行时动态分配的内存。
-
管理方式:
- STM32的堆:由C库函数(如
malloc
和free
)进行管理和操作,这些函数负责分配和释放内存。 - FreeRTOS的堆:由FreeRTOS系统进行管理,提供了更高级的内存管理机制,包括内存碎片的预防和处理等。在FreeRTOS中,程序员通常使用
pvPortMalloc
和vPortFree
等函数来分配和释放内存。
- STM32的堆:由C库函数(如
-
在系统中的作用:
- STM32的堆:它是STM32微控制器内存管理的一部分,提供了用户程序所需的动态内存分配功能。
- FreeRTOS的堆:它是FreeRTOS实时操作系统的一部分,为任务提供了动态内存的管理机制,帮助确保任务的独立性和安全性。在嵌入式系统中,实时操作系统通常用于管理多个并发任务,而FreeRTOS堆则是这些任务之间进行内存分配和共享的关键组件
所以,我们在使用pvPortMalloc申请内存的时候,只需要注意加起来总量不超过configTOTAL_HEAP_SIZE设置的堆空间即可,不用管
Stack_Size设置的大小,Stack_Size只和标准库malloc有关。
3.2栈的大小设置
栈的话,默认配置是0x400,一般小项目都是用这个配置,大项目一般用0x1000这个样子也完全够用了,我们平时写程序的时候,要注意局部变量过大和函数参数直接传递结构体,比如
void func(void){
u8 bufs[512];
}
一下子就占用了512个字节,如果再加上一些其他变量,很容易超出默认定义的栈空间1024字节,传递结构体会消耗对应结构体大小的栈空间,如果再出现函数嵌套和递归,就更容易出现栈泄露的问题了。
总之,就是堆空间大小取决于你想使用标准库malloc申请内存的大小,栈空间大小取决于局部变量、函数参数以及函数返回地址等信息的总和,大项目要对栈空间分配多一些,不然实际使用大于设置的大小都会使程序崩溃。。。