STM32内存管理详解:栈、堆、数据段、bss段、代码段及字符串的内存分配策略
1. 栈(Stack)
功能
栈主要用于支持函数调用和返回机制,在函数调用过程中,它会存储函数的局部变量、函数参数、返回地址以及寄存器的上下文信息。当一个函数被调用时,系统会在栈上为该函数分配一块连续的内存空间,用于存放这些临时数据;当函数执行完毕返回时,这块内存空间会被自动释放。
分配与管理
栈的内存分配和释放是由编译器自动完成的,遵循后进先出(LIFO)的原则。每当有新的函数调用发生时,栈指针会向下移动,为新的局部变量和参数分配空间;函数返回时,栈指针会向上移动,回收之前分配的空间。
存储位置
栈通常位于 SRAM 中,因为 SRAM 具有高速读写的特性,能够满足函数调用时对数据快速存取的需求。
大小限制
栈的大小一般是在编译时确定的,由芯片的内存布局和编译器的设置共同决定。如果在程序运行过程中栈的使用超出了其预先分配的大小,就会发生栈溢出错误,可能导致程序崩溃。
2. 堆(Heap)
功能
堆用于动态内存分配,允许程序在运行时根据实际需要申请和释放内存空间。这对于那些在编译时无法确定所需内存大小的情况非常有用,例如创建动态数组、链表等数据结构。
分配与管理
堆的内存分配和释放需要程序员手动进行操作,通常使用标准库函数 malloc()、calloc()、realloc() 来申请内存,使用 free() 来释放内存。这些函数会在堆中寻找合适的空闲内存块进行分配或释放,并维护堆的内存管理信息。
存储位置
堆同样位于 SRAM 中,因为它需要在程序运行时进行频繁的读写操作,SRAM 的高速特性能够满足其性能要求。
潜在问题
由于堆的内存管理需要程序员手动控制,如果使用不当,容易出现内存泄漏(申请的内存没有及时释放)或内存碎片(堆中存在大量不连续的小空闲块,导致无法分配足够大的连续内存)等问题。
3. .data 段
功能
.data 段用于存储已初始化的全局变量和静态变量。这些变量在程序编译时就已经被赋予了初始值,并且在程序运行期间其值可以被修改。
存储位置与加载过程
初始化值存储:在编译后的可执行文件中,.data 段变量的初始化值被存储在 Flash 中,因为 Flash 具有非易失性,能够在系统断电后保存数据。
运行时加载:在程序启动阶段,当加载链接文件时,系统会将 Flash 中 .data 段的初始化值拷贝到 SRAM 中的相应位置。这样,程序在运行时就可以直接在 SRAM 中对这些变量进行读写操作,提高了数据访问的速度。
特点
.data 段中的变量占据固定的内存空间,其大小在编译时就已经确定,直到程序结束才会释放。
4. .bss 段
功能
.bss 段用于存储未初始化的全局变量和静态变量。在 C 语言中,这些变量会被默认初始化为 0 或空值。
存储位置
.bss 段只存在于 SRAM 中,与 Flash 没有直接关系。虽然这些变量在可执行文件中并没有实际的初始化值,但在程序启动时,系统会自动将 .bss 段所占用的 SRAM 区域清零,为这些变量分配内存并初始化为 0。
变量类型信息
变量的类型信息在编译时被记录在可执行文件中,存储在 Flash 上。编译器会根据变量的类型为其分配相应大小的内存空间,并在生成的目标代码中处理与类型相关的操作。
优点
由于 .bss 段中的变量在可执行文件中不占用实际的存储空间,只在运行时在 SRAM 中分配空间,因此可以节省可执行文件的大小。
5. text 段(包含代码和字符串常量等)
功能
text 段主要存储程序的可执行代码以及字符串常量等。程序中的函数、指令等都存放在这个段中,是程序运行的核心部分。
存储位置
text 段通常存储在 Flash 中,因为 Flash 具有非易失性,能够在系统断电后保存程序代码。在程序启动时,CPU 会从 Flash 中读取 text 段的代码并执行。
特点
只读性:text 段通常是只读的,在程序运行过程中不会被修改,以保证程序代码的完整性和稳定性。
大小固定:其大小在编译时就已经确定,由程序的代码量和字符串常量的数量等因素决定。
作者:@MengZhongHua