打印
[疑难问答]

单片机的堆和栈(Heap & Stack)

[复制链接]
3264|40
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
jonas222|  楼主 | 2024-1-29 21:44 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
一、程序内存分配
由c/C++编译的程序占用的内存分为以下几个部分
1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放
4、文字常量区—常量字符串就是放在这里的。 程序结束后由系统释放
5、程序代码区—存放函数体的二进制代码。
二、在单片机中内存如何储存
以STM32单片机为例:
                                                        STM32的地址空间映射图
我们可以看到代码存储区域在CODE区域;
STM32的堆栈是存放在片上静态SRAM中的,地址分配可以见Keil的编译map文件:
代码来源地址:https://download.csdn.net/download/emoeror_zhang/11286638
   HEAP                                     0x20000148   Section      512  startup_stm32f10x_hd.o(HEAP)
   STACK                                    0x20000348   Section     1024  startup_stm32f10x_hd.o(STACK)
    __initial_sp                             0x20000748   Data           0  startup_stm32f10x_hd.o(STACK)
上面节选中, HEAP是堆的基地址,__initial_sp  是栈指针 。示意图如下:
   
三、堆栈地址的设置
    在上述图和map中,我么可以看到堆的大小是0线0x200,也就是在0x20000148-0x20000348之间,而栈的地址大小是0x400,也就是在0x20000348-0x20000748。为什么他们的大小是这样的,是怎么由来的呢?
    打开汇编文件startup_stm32f10x_hd.s,我们可以找到相对应的设置堆栈大小的程序,如图:
    堆和栈,一般堆是由低地址往上增长,栈是由往下减少。都是连续的,C语言不提供内存保护机制类似的功能,如果堆一直增长,栈一直申请,然后就会导致栈溢出,从而导致程序崩溃。
四、变量储存位置分析
    同样的,我们还是以上述的map文件为例子进行分析。
   基础知识:   

  • .data: inited ,通常是指用来存放程序中已初始化的全局变量的一块内存区域。数据段属于静态内存分配

  • .bss:zero,通常是指用来存放程序中未初始化的全局变量的一块内存区域。BSS是英文BlockStarted by Symbol的简称。BSS段属于静态内存分配。

  • cstack:函数局部变量用的区域,所有的功能函数使用的局部变量都是从这个堆栈申请使用的,用完了再还回去。子函数里面用到的局部变量都是在这里面取来用的

   如图所示,fac_ms和fac_us 在程序中是static变量类型,储存在0x20000000-0x20000148之间的位置,fac_ms在0x20000016,fac_us在0x20000014,那其他的地址处是什么数据呢?
   继续在map里面寻找,找到如下图所示:
     发现其余的地质处储存了全局变量数组,以及引用的库文件的全局变量。
     在map里面我们看到,全局变量和静态变量储存的位置,和堆栈无关,那么堆栈储存的内容是什么呢?
五、堆栈存放内容
1、栈区
      存放函数的参数值,局部变量的值等等临时变量,退出该作用域该临时变量就会自动释放。
2、堆区
     系统会给每个程序分配一部分栈空间让他们能够运行起来,问题就是栈空间必然存在不够用的问题,而堆不属于程序,堆是独立的,是公用的。只要你malloc(sizeof(SIZE_YOU_WANT)),就可以得到相应一部分的堆空间。
    简单的来说,就是当你使用的时候malloc申请一部分空间来使用,但是别忘记了使用完成之后free掉,不然往往会堆溢出,占用了栈的位置空间,导致程序奔溃。
总结:
     如果我们设置了堆的空间大小,但是我们程序中没有进行malloc申请,那么在程序事假运行的时候,我们栈的空间超过本身设置的空间,进入到堆里面,那么程序是不会出错的,但是超过了堆的空间了,进入到全局变量区域,就会出现莫名其妙的错误。
     不使用malloc,我们可以将堆设置成0,这是没有问题的,但是栈的空间大小要设置成合适的,不然就会因为栈溢出,进入harderror,程序奔溃。

使用特权

评论回复
沙发
tpgf| | 2024-2-5 11:00 | 只看该作者
栈由操作系统自动分配释放,用于存放函数的参数值、局部变量等,其操作方式类似于数据结构中的栈

使用特权

评论回复
板凳
renzheshengui| | 2024-2-5 11:37 | 只看该作者
栈内存是由系统分配,系统释放的;以函数为单位进行栈内存分配,函数栈帧,局部变量,形参变量等都存放在栈内存上

使用特权

评论回复
地板
paotangsan| | 2024-2-5 20:07 | 只看该作者
堆由程序员分配释放,若程序员不分配释放,程序结束时由操作系统回收,其分配方式类似于链表。

使用特权

评论回复
5
wakayi| | 2024-2-5 20:43 | 只看该作者
堆内存是由用户自己分配的, C 语言用 malloc/free进行分配释放

使用特权

评论回复
6
wowu| | 2024-2-5 21:17 | 只看该作者
栈的内存分配释放速度快效率高,内存都是连续的;堆内存的分配释放相对于栈来说效率低一些,内存不一定连续,容易产生内存碎片,但是灵活性高

使用特权

评论回复
7
xiaoqizi| | 2024-2-5 21:51 | 只看该作者
栈本身也是一种线性表,只不过是有限制的

使用特权

评论回复
8
beacherblack| | 2024-3-4 17:03 | 只看该作者
使用C语言中的malloc()和free()函数可以在堆上分配和释放内存。堆上的内存管理更为灵活,但也需要更精细的控制,以防止内存泄漏或碎片化的发生。

使用特权

评论回复
9
tabmone| | 2024-3-5 12:42 | 只看该作者
在单片机编程中,堆(Heap)和栈(Stack)是内存中用来存储数据的两个不同的区域,它们在内存管理中扮演着重要的角色。

使用特权

评论回复
10
jonas222|  楼主 | 2024-3-5 12:50 | 只看该作者
堆常用于动态创建大型数据结构(如链表、树、动态数组等)、在运行时动态生成较大数据块等情况。

使用特权

评论回复
11
mollylawrence| | 2024-3-5 17:00 | 只看该作者
对于生命周期较短、空间需求较小的数据,可以使用栈内存进行存储。
对于生命周期较长、空间需求较大的数据,可以使用堆内存进行存储。
在使用堆内存时,应注意避免内存泄漏和碎片化问题,确保及时释放不再使用的内存。

使用特权

评论回复
12
lzbf| | 2024-3-10 11:06 | 只看该作者
栈的主要特点如下:

存储空间有限,通常由编译器在编译过程中确定。
数据存储速度快,因为栈在内存中的分配和释放由编译器自动完成。
数据存储空间连续,有利于CPU进行寻址操作。

使用特权

评论回复
13
mollylawrence| | 2024-3-10 22:19 | 只看该作者
堆内存的分配和回收相对栈内存更为复杂,因为它需要程序员手动管理。堆内存的增长方向一般为向高地址方向增长,而且分配和回收可能导致碎片化。

使用特权

评论回复
14
hearstnorman323| | 2024-3-11 16:21 | 只看该作者
堆是用于动态内存分配的区域,程序员通过函数(如C语言中的malloc、calloc、realloc和free等)在运行时动态申请和释放内存。堆内存可以用来存储那些在编译期无法确定大小的数据结构。

使用特权

评论回复
15
wangdezhi| | 2024-3-11 20:14 | 只看该作者
了解这些内存区域的特点和用途,对于优化单片机程序的内存使用、提高程序运行效率具有重要意义。

使用特权

评论回复
16
uiint| | 2024-3-14 12:14 | 只看该作者
内存由编译器自动分配和释放,主要用于存放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈。

使用特权

评论回复
17
linfelix| | 2024-3-14 15:03 | 只看该作者
栈通常比堆更快,因为堆需要进行内存分配和释放操作。

使用特权

评论回复
18
gygp| | 2024-3-14 17:41 | 只看该作者
栈是单片机内存中用于存储函数调用时临时数据的区域。栈内存的管理通常是自动的,由编译器和运行时环境负责。当函数被调用时,它的参数、局部变量以及返回地址通常会被压入栈中。当函数执行完毕后,这些数据会从栈中弹出,以便为下一个函数调用腾出空间。

使用特权

评论回复
19
belindagraham| | 2024-3-14 22:06 | 只看该作者
通常情况下,栈用于存储临时变量和函数调用过程中的数据,而堆用于存储程序运行过程中的动态数据,如动态分配的数组、链表等。在编程时,需要注意堆栈空间的使用情况,避免出现栈溢出或内存泄漏等问题。

使用特权

评论回复
20
sdlls| | 2024-3-15 13:14 | 只看该作者
堆是一种先进先出(FIFO)的数据结构,用于存储程序运行过程中的动态数据。堆区一般由程序员分配和释放,若程序员不释放,程序结束时可能由操作系统回收。分配方式类似于数据结构中的链表。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

23

主题

1355

帖子

0

粉丝