当前位置:首页 > > TopSemic嵌入式
[导读]可能很多人心中都有一个武侠梦,记得小时候搬个小凳子,到邻家院子里蹭电视看,正值金庸先生的射雕英雄传热播,一伙人屏息静气,全神贯注,随着郭靖黄蓉出山入海,驰骋大漠。然后觉得自己比憨憨的郭大侠,还是要聪明一点点,于是找来布袋子,装上沙子,苦练武功。如今想来奇怪,怎么单练这铁掌帮的功夫呢?真是好坏不分,值得检讨。

可能很多人心中都有一个武侠梦,记得小时候搬个小凳子,到邻家院子里蹭电视看,正值金庸先生的射雕英雄传热播,一伙人屏息静气,全神贯注,随着郭靖黄蓉出山入海,驰骋大漠。然后觉得自己比憨憨的郭大侠,还是要聪明一点点,于是找来布袋子,装上沙子,苦练武功。如今想来奇怪,怎么单练这铁掌帮的功夫呢?真是好坏不分,值得检讨。

此去经年,武侠梦碎。没办法华山论剑,只能论一下栈了。

  1. 什么是堆栈

我们说堆栈,其实堆是堆(Heap),栈是栈(Stack)。一般我们写程序时不太关心堆栈,因为编译器会帮我们处理。但是还是有必要把它们弄清楚,不然有时候出了莫名其妙的问题,会无从下手。比如说堆栈溢出,就好比一个幽灵,非常难发现。看起来一切都挺好,程序编译运行,测试,可能都好好的,直到它突然出现,发出致命一击,导致系统崩溃。

先看一个典型的存储器示意图,编译器把RAM划分为静态存储区,堆区,栈区。静态存储区用于存放全局变量,静态变量,编译的时候它的大小也就确定了;紧挨着的是堆(Heap)区,由程序调用malloc,free等函数来分配和释放;栈区由编译器自动分配和释放,用来传递参数,存放局部变量等。栈比较特殊,正常情况下,它是后进先出的。

栈的使用是从高地址,也就是Top of Stack开始,向下增长。

那为什么要把局部变量分配在栈里呢?因为单片机访问栈用的指令,和访问全局变量区域用的指令是不一样的,访问栈的指令速度更快。再一个就是这些局部变量,只有所在函数被调用的时候才会分配,函数返回时分配的空间就被收回了,不像全局变量始终占用内存。

我们看一个程序,用到了比较多种类的变量类型。

编译后的map文件:

我们可以看到全局变量,还有静态局部变量都放到了静态存储区。非静态的局部变量在map文件是找不到的。

特别关注一下P1这个指针型变量,因为它是全局变量,所以变量本身分配在静态存储区,但是它指向的用Malloc申请的内存,是在堆区。如下图:

  1. 堆栈溢出

堆栈溢出,主要是指栈溢出。因为我们在堆中,用malloc, 或new函数申请内存时,如果空间不够了,函数会返回NULL,很清楚它的空间不够了。而栈由于是函数调用时分配,占用空间大小跟调用深度有关,编译器很难确定最大需要多少空间。如果栈空间过小,直接的结果就是当栈增长超过栈底,堆中的数据,甚至是静态存储区数据被冲掉,导致不可预知后果。

那怎么避免堆栈溢出,至少知道发生了堆栈溢出呢?

一个就是在启动文件里,把堆栈的值尽量改大。编译的时候用 –info=stack可以大概看一下,各个函数占用栈的大小。

综合编译后RAM剩余空间的大大小,可以直接把栈空间放到最大。在下面的源文件中可以直接修改堆和栈的大小。对于静态存储空间,编译器会根据实际使用大小进行分配,我们不用关心。

还有一个方法,在栈底放置特殊字符,然后在程序运行过程中,监测特殊字符是否被更改,如果被更改,大概率是发生了栈溢出,此时可以采取一定的补救措施。如何操作呢?先在启动文件用EXPORT Stack_Mem导出栈底,在主程序定义同名外部函数extern void Stack_Mem(void); 然后就可以往栈底写入数据了,参见前面的程序。

这种方法的缺点就是,跑飞了的野指针,也可能篡改这一区域数据,造成误判。还有一个就是,因为做数据比较判断,要消耗CPU时间,一般只能周期性检测,在没检测出问题之前,栈溢出有可能已经造成程序出问题了。你用过更好的方法吗?欢迎一起来探讨。


本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭