STM32的堆与栈

本文详细介绍了堆和栈的概念及其区别,包括它们的空间分配方式、变量类型及如何避免溢出等问题。并通过实例帮助读者理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       声明:博文内容有参考其它牛人的博客或资料,参考均已在最后列出。  

       上一篇博客解决了因为堆栈的设置空间不够而引发的“命案”,这次我们就来看看它的“杀人动机”。

首先我们来认识一下堆与栈的含义():​

​(1)栈区(stack):由编译器自动分配和释放,存放函数的参数值、局部变量的值等,其操作方式类似于数据结构中的栈。

(2)堆区(heap):一般由程序员分配和释放,若程序员不释放,程序结束时可能由操作系统回收。分配方式类似于数据结构中的链表。

(3)全局区(静态区)(static):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系统自动释放。

(4)文字常量区:常量字符串就是存放在这里的。

(5)程序代码区:存放函数体的二进制代码。

解释的名词有点多了,但这不是重点,重点是看例子!

例子对上面的名词有了充分的解释。

所以堆和栈的区别:

       stack的空间由操作系统自动分配/释放,heap上的空间手动分配/释放。

       stack的空间有限,heap是很大的自由存储区。

       程序在编译期和函数分配内存都是在栈上进行,且程序运行中函数调用时参数的传递也是在栈上进行。

为了更好的了解这些东西,我们来查看,map文件中的内容。

找到相关的有用信息​


​       显然__initial_sp是堆栈指针他就是FLASH的0x8000000地址的前面4个字节(他根据堆栈大小有便器自动生成)

从中可以看出对于HEAP堆的起始地址(Base Addr)是0x200000a8,占0x200,而STACK栈的起始地址(Base Addr)是0x200006a8.(因为 栈是向下增长)

显然堆与栈是相邻的。以一个图来说明(没错,这是别人做的图,,,,)

​堆和栈空间分配

       栈:向低地址扩展    0x200006a8---------->0x200002a8

       堆:向高地址扩展    0x200000a8---------->0x200002a8(好像堆应该是没有方向的吧,这里我不太清楚)

堆和栈变量

       栈:临时变量,退出该作用域就会自动释放

       堆:malloc变量,通过free函数释放

       另外:堆栈溢出,编译不会提示,需要注意

看到比较有意思的别人关于堆与栈的解释(好吧,就当复习一下上面的介绍)

栈:存函数的临时变量,即局部变量,函数返回时随时有可能被其他函数栈用。所以栈是一种分时轮流使用的存储区,编译器里定义的Stack_Size,是为了限定函数的局部数据活动的范围,操过这么范围有可以跑飞,也就是栈溢出;Stack_Size不影响Hex,更不影响Hex怎么运行的,只是在Debug调试时会提示错。栈溢出也有是超过了国界进行活动,只要老外没有意见,你可以接着玩,有老外不让你玩,你就的得死,或是大家都死(互相撕杀),有的人写单片机代码在函数里定义一个大数组 int buf[8192],栈要是小于8192是会死的很惨。

 :存的是全局变量,这变量理论上是所有函数都可以访问的,全局变量有的有初始值,但这个值不是存在RAM里的,是存在Hex里,下载到Flash里,上电由代码(编译器生成的汇编代码)搬过去的。有的人很“霸道”,上电就霸占已一块很大的RAMHeap_Size),作为己有(malloc_init),别人用只能通过他们管家借(malloc),用完还得换(free)。所以  一旦有“霸道”的人出现是编译器里必须定义Heap_Size,否则和他管家借也没有用。


好了,本篇大概就讲这么多,下一篇大概讲讲Core_cm3.c​


参考:

​1、http://blog.sina.com.cn/s/blog_542bad910101nboa.html

2、​http://blog.youkuaiyun.com/slj_win/article/details/16906141


<think>首先,用户的问题是:“我想理解STM32中的内存管理机制请问STM32的区别及内存管理机制”。我需要基于提供的引用和系统指令来回答。 系统指令包括: -所有行内数学表达式用$...$格式。-独立公式用$$...$$格式并单独成段。 -LaTeX语法正确。-使用中文回答。-生成相关问题。 -回答中引用的段落末尾自然地添加引用标识,例如[^1]。用户可见层指令: -回答结构清晰,帮助用户逐步解决问题,尽量保证回答真实可靠。 提供的引用:- [^1]:关于内存碎片和malloc分配。 -[^2]:内存管理的定义和malloc/free函数。- [^3]: STM32的大小设置,单位是字(4字节)。- [^4]: FreeRTOS内存管理,不使用标准C库的原因。我需要结构化回答:1.**解释的区别**:基于引用。 2. **描述STM32中的内存管理机制**:包括的设置、使用场景。 3. **讨论内存管理问题**:如碎片、泄漏,基于引用。4.**引用相关部分**:在回答中自然地添加引用标识。 回答结构:-引言:简要介绍STM32中的作用。-的区别:详细对比。 -STM32中的内存管理:如何设置大小,使用malloc/free。 -实际问题和优化:碎片、泄漏,以及FreeRTOS中的处理。-总结。生成相关问题:-在回答结束后,添加“相关问题”部分。使用中文回答。 关键点从引用:-(Stack):用于局部变量、函数调用等,大小在启动文件中设置,如Stack_SizeEQU0x00000800表示2048字节(因为一个字4字节)[^3]。 -(Heap):用于动态内存分配,大小在启动文件中设置,如Heap_SizeEQU0x00000200表示512字节[^3]。-内存管理:malloc和free函数用于分配和释放内存[^2]。 -问题:内存碎片(fragmentation)导致无法分配连续内存,即使总空间足够[^1];标准C库不适合嵌入式系统,因为代码大、非线程安全、运行不确定[^4]。步骤: 1. **(Stack)**:-用于存储局部变量、函数参数、返回地址。-大小固定,在编译时确定(启动文件)。-在STM32中,大小以字为单位,每个字4字节。 2. **(Heap)**:-用于动态内存分配(如malloc)。-大小固定,在启动文件中设置。-使用malloc和free管理。3.**区别**:-:自动管理(LIFO),速度快,但大小固定。-:手动管理(通过malloc/free),灵活,但可能碎片化。 4. **内存管理机制**:-在裸机STM32中,使用启动文件定义堆栈大小。-动态内存分配通过malloc/free,但可能导致碎片[^1]。-在FreeRTOS中,有特殊内存管理机制避免标准C库问题[^4]。 5. **引用整合**:-提到碎片时引用[^1]。-提到malloc/free时引用[^2]。-提到堆栈大小时引用[^3]。-提到FreeRTOS时引用[^4]。生成相关问题: -基于主题,如如何优化大小、处理内存碎片、FreeRTOS内存管理等。 最终回答结构: -解释。-区别。- STM32中的设置。 -管理机制和问题。-相关问题。</think>### STM32中的内存管理机制 在STM32微控制器中,(Stack)和(Heap)是内存管理的两个核心部分,它们在嵌入式系统中扮演不同角色。STM32通常使用ARM Cortex-M内核,内存管理依赖于启动文件和运行时库(如标准C库或RTOS专用机制)。下面我将逐步解释的区别、内存管理机制,并结合实际引用进行分析。 #### 1. **的基本区别** 在内存分配方式、管理机制和使用场景上有本质不同: - **(Stack)**: - **作用**:用于存储局部变量、函数参数、返回地址和中断上下文。是LIFO(后进先出)结构,由编译器自动管理。 - **特点**: - 分配和释放速度快(通过硬件指令自动处理)。 - 大小固定,在编译时通过启动文件(如`startup_stm32fxxx.s`)定义。 - 溢出风险高:如果空间不足,会导致程序崩溃(如HardFault错误)。 - 在STM32中,大小以字(Word)为单位定义,每个字为4字节。例如,引用[^3]中提到:`Stack_Size EQU 0x00000800` 表示大小为 $0x800 \times 4 = 2048$ 字节。 - **适用场景**:函数调用、中断处理等短期数据存储。 - **(Heap)**: - **作用**:用于动态内存分配(如通过`malloc`和`free`函数),允许在运行时请求和释放内存块。 - **特点**: - 分配和释放由程序员手动控制(需调用`malloc`/`free`)。 - 大小固定,同样在启动文件中定义(如`Heap_Size EQU 0x00000200` 表示大小为 $0x200 \times 4 = 512$ 字节)[^3]。 - 灵活但易碎片化:多次分配和释放后,空闲内存可能不连续,导致无法分配大块内存(即使总空间足够),这称为内存碎片(memory fragmentation)[^1]。 - 管理开销大:需要额外的算法(如链表)来跟踪空闲块。 - **适用场景**:动态数据结构(如链表、队列)或不确定大小的数据缓冲区。 **关键区别总结**: | 特性 | (Stack) | (Heap) | |--------------|--------------------------------|--------------------------------| | **管理方式** | 自动(编译器/硬件) | 手动(程序员调用 malloc/free) | | **速度** | 快(硬件支持) | 慢(运行时算法) | | **大小** | 固定(编译时确定) | 固定(但可动态分配块) | | **碎片风险** | 低(连续分配) | 高(可能碎片化)[^1] | | **溢出影响** | 程序崩溃 | 内存泄漏或分配失败 | #### 2. **STM32中的内存管理机制** 在STM32裸机(无操作系统)或RTOS环境中,内存管理主要通过以下方式实现: - **启动文件配置**: - 的大小在汇编启动文件(如`.s`文件)中定义。STM3232位架构,因此单位是字(4字节)。例如: - `Stack_Size EQU 0x00000800` 定义了2KB空间。 - `Heap_Size EQU 0x00000200` 定义了512字节空间[^3]。 - 这些值在链接阶段被写入内存映射,通常位于内存起始地址(如`0x20000000`),紧随其后。 - **动态内存分配**: - 使用标准C库的`malloc`和`free`函数进行管理。内存管理的主要目标是高效分配和回收资源[^2]。 - 问题:在嵌入式系统中,标准`malloc`可能导致: - **内存碎片**:例如,如果已分配的内存块不连续,即使剩余空间总和足够,也无法分配新的大块内存(如引用[^1]中所述:分配12字节失败,尽管剩余13字节但非连续)。 - **内存泄漏**:未释放的内存会永久占用空间,导致资源耗尽[^1]。 - **运行不确定性**:分配时间不可预测,不适合实时系统[^4]。 - **FreeRTOS中的优化**: - 在运行FreeRTOS的STM32中,通常不使用标准C库的`malloc`,而是采用定制内存管理算法(如heap_4.c),原因包括: - 减少代码大小和碎片化风险。 - 提供线程安全机制(避免多任务竞争)。 - 例如,FreeRTOS使用双机制(主和任务)来隔离任务内存[^3][^4]。 - **内存分区**: - STM32内存通常分为: - **代码区**:存储程序代码。 - **数据区**:全局和静态变量。 - **区**:自动管理。 - **区**:动态管理。 - 引用[^2]强调,内存管理通过`malloc`和`free`实现,但需注意分区边界。 #### 3. **常见问题最佳实践** - **内存碎片**:频繁的`malloc/free`会导致碎片化。解决方案包括: - 使用固定大小内存池(如FreeRTOS的pvPortMalloc)。 - 避免小内存块的反复分配[^1]。 - **溢出**:如果函数嵌套太深或局部变量过大,会触发HardFault。可通过调试器(如ST-Link)监控使用。 - **大小设置**:在资源受限的STM32中(如只有几十KB RAM),不宜过大。例如,512字节适用于小规模动态分配,但需根据应用调整。 - **FreeRTOS优势**:其内存管理算法更轻量,减少碎片和不确定性[^4]。 总之,的核心区别在于管理方式:是自动、高效的短期存储,是手动、灵活的长期存储。在STM32中,合理配置大小并优化内存管理算法(如使用RTOS)是关键。内存泄漏和碎片是常见挑战,需通过代码规范和工具(如内存分析器)来缓解[^1][^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值