嵌入式——什么是堆、什么是栈

嵌入式


堆(Heap)和栈(Stack)是计算机内存中两种不同的数据存储方式。

一、什么是堆

(1)堆是一种内存管理方式,其内存空间不是连续的,而是杂乱无章的,通过指针来定位数据的存储位置。堆用于动态分配内存,可以根据需要动态地分配和释放内存。堆的大小通常受到计算机系统中物理内存和虚拟内存的限制。其特点就是自由(随时申请、释放、大小块随意)。
(2)堆内存是操作系统划分给堆管理器(操作系统的一段代码,属于操作系统内存管理单元)来管理的,然后向使用者(用户进程)提供API(malloc和free)来使用堆内存。
(3)什么时候需要使用堆内存?需要内存容量比较大时、需要反复使用及释放时,很多数据结构(譬如链表)的使用都需要使用堆内存。
2.堆内存管理的特点
(1)容量不限(常规需求都能满足)。
(2)申请及释放都需要手动进行,若使用完后没有释放则会造成内存泄漏,内存泄漏的堆积会导致内存溢出甚至系统崩溃。
3.C语言操作堆内存的接口
(1)堆内存申请时有三个功能类似的函数:malloc、calloc、realloc。

void *malloc(size_t size);              // 申请指定大小的内存
void *calloc(size_t nmemb, size_t size);  // 申请nmemb个内存单元,每个size字节
void *realloc(void *ptr, size_t size);     // 改变已经申请的空间的大小

(2)堆内存释放最简单,直接调用free函数即可。

void free(void *ptr);

(3)代码示例:
// 譬如要申请10个int元素的内存

malloc(40);
calloc(10, 4);

(4)C语言定义数组时必须给出数组元素个数,且无法再修改。而在Java等高级语言中,则可以修改数组大小,其原理是重新创建一个新的数组,然后释放掉原数组。realloc的实现原理也类似。

二、什么是栈

1.什么是栈?
(1)栈是一种数据结构,遵循后进先出(Last In, First Out,LIFO)的原则。
栈用于存储函数调用的局部变量、函数参数、函数返回地址以及临时数据。栈的大小是有限制的,通常由操作系统预先分配好。栈的分配和释放是由编译器自动管理的。当进入一个新的函数作用域时,局部变量和函数参数会被压入栈中;当函数退出作用域时,栈会自动弹出这些数据,以便为下一个函数调用做准备。

void func1() {
    int x = 1; // x 被压入栈中
    // ...
} // x 从栈中弹出

2.栈管理内存的特点(小内存、自动化)
(1)先进后出(FILO),而队列是先进先出(FIFO)。
(2)栈的特点是入口即出口,只有一个口,另一个口是堵死的,所以是先进后出。而队列的特点是入口和出口都有,必须从入口进去,从出口出来,所以是先进先出。
3.栈的应用举例:局部变量
(1)C语言中的局部变量是用栈来实现的,定义局部变量时,对应操作是入栈(自动化);函数退出局部变量注销的时候,对应的操作是出栈(自动化)。
(2)栈的优点:方便,分配和回收都不用程序员自己操作,C语言自动完成。
(3)定义局部变量但未初始化,值是随机的,为什么?
因为栈是反复使用的,并且每次使用完之后没有清零。
4.栈的优势和劣势
(1)优势:自动化,不用程序员手动操作内存。
(2)劣势:首先,栈是有大小的,所以栈内存大小不好设置。所以太小怕溢出,太大怕浪费内存(与数组类似)。其次,栈溢出的危害很大,一定要避免。所以我们在C语言中定义局部变量时不能定义太多或者太大(譬如不能定义int a[10000];使用递归来解决问题时一定要注意递归收敛)。

总结

区别和联系:

1.存储方式:栈是一种线性的存储结构,而堆是一种树状的存储结构。
分配和释放:栈的分配和释放是由编译器自动管理的,而堆需要手动分配和释放。
2.空间大小:栈的大小通常是固定的,由操作系统预先分配,而堆的大小受到物理内存和虚拟内存的限制。
3.数据生存周期:栈中的数据生命周期与其所在函数的执行周期相关联,函数执行完毕时,栈中的数据会被自动释放;而堆中的数据可以在程序的任意阶段使用,并且需要手动释放以避免内存泄漏。

总的来说,栈主要用于存储函数调用相关的数据,而堆则用于动态分配内存以存储动态数据。

### STM32 中的概念 #### 的作用与配置方法 在嵌入式系统中,特别是像STM32这样的微控制器平台,用于动态内存分配。这意味着当程序运行时可以根据需求申请一定大小的连续存储区域。这种灵活性使得复杂的数据结构(如链表、树形结构等)能够被创建并管理。 对于STM32而言,默认情况下其启动文件已经定义了一定数量的空间作为heap区,并指定了起始地址。例如,在某些型号中可以看到如下设置: ```assembly HEAP 0x200106f8 Section 512 startup_stm32f2xx.o(HEAP)[^4] ``` 这表明从`0x200106f8`开始有512字节可用作空间。然而,实际应用过程中可能需要调整这个数值以适应具体应用场景的需求;如果应用程序频繁地进行大量的动态内存操作,则应适当增加容量以免发生溢出错误。 为了修改默认设定,可以在链接脚本(.ld)内重新指定heap段的位置及其长度。通常做法是在`.isr_vector`之后紧跟`.data`, `.bss`等静态数据段放置heap部分。 #### 的作用与配置方法 相比之下,主要用于函数调用期间保存返回地址、参数传递以及临时变量存储等功能。每当进入一个新的子过程执行前都会先压入当前上下文环境至顶位置以便后续恢复现场之需。因此随着递归深度加大或局部对象增多,所需占用的stack资源也会相应增长。 同样地,在startup代码中有预设好的STACK初始化语句: ```assembly STACK 0x200108f8 Section 1024 startup_stm32f2xx.o(STACK) ``` 上述片段说明了初始状态下为预留了自`0x200108f8`起共计1KB (即1024 bytes) 的RAM区间供使用。不过值得注意的是,由于大多数MCU内部SRAM总量有限,所以合理规划各模块间共享这部分宝贵资产显得尤为重要——过大的尺寸不仅浪费硬件资源还可能导致其他重要组件无法获得足够的工作缓冲区而引发异常状况。 针对不同版本系列的产品手册会给出建议性的最大允许范围值,开发者应当依据实际情况灵活调配二者之间的比例关系。另外一种有效手段就是借助编译工具生成的地图(map)文档来精确分析整个工程所消耗的具体情况从而做出最优决策[^5]。 ### C语言中的全局变量、局部变量区别于特性 除了理解本身外,掌握它们与其他类型的变量之间相互作用也是至关重要的知识点之一。简单来说: - **全局/静态变量** 存储于特定的数据段而非活动记录之中; - **自动型局部实体** 则完全依赖于对应层次框架内的私有工作区实现生命周期管理访问控制机制。 综上所述,通过精心设计布局方案可以显著提升系统的稳定性性能表现[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我与nano

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值