0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

关于堆栈的深入理解

0BFC_eet_china 来源:未知 作者:邓佳佳 2018-03-04 15:57 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

一、这些个概念怎么来的以及怎么记得住

这里,只限于整理我个人对堆/栈/堆栈在内存管理方面的理解。其他,在数据结构方面讲的堆/栈目前不在我整理范围之内。

这里提了三个概念: 堆,栈,以及堆栈。我把栈和堆栈的概念等同了。所以,接下来只要把两个概念弄清楚就可以了:堆和栈。

先说由来。由于我的工作大部分是和单片机相关的,因此也是基于嵌入式的这个方面的理解。

每片MCU有一定的内存,这些内存分:程序存储区;数据存储区。举例就是:我们写的每行代码,都会保存到程序存储区里面;而定义的一些全局变量,静态变量,局部变量之类的,就保存到数据存储区。

程序存储区,对于写代码的人来说,可以说是黑盒子:只要你的代码不超过程序代码空间,everything will be fine. 代码究竟是如何执行的,取决于你的编程思想,就是说,你让程序往东走,它就会往东走;让它原地踏步,它也会照做;前提是你的代码要写好。所以,对于编程经 验成熟的人,同样的算法,他可能会少敲几行代码,并且算法出错的几率少一些;不怎么会编程的人,就多敲几行,多测试一下。研究深一些的人,可能还会对代码 执行效率深入研究。我决定就此止步。继续黑盒子的话题,程序员的代码会烧写到程序存储区里面,至于哪条语句存哪里,这个是不用研究的。反正,一旦发现软件 没按照你设计的那样跑,基本就是程序自身的问题,不是存放程序的存储区的问题。

数据存储区,让程序员发挥的空间就很大了。由于程序是动态地执行的,执行的结果是怎么样,会产生什么数据就不是一个确定的事情。

举个例子说说这个程序和数据之间的表象吧。举例的事件就是:一个MP3播放器的上/下键的操作。加入在播放器里有10首歌,若当前是第3首,那 么按下[上]键后,应该是播放第2首。因此,实现播放第2首的,就是程序员写程序实现的,他的代码让[上]键实现了能从第3首切换到第2首的操作。这里, 表现的就是代码。而且,这个代码是确切的行为,从第3首按了[上]键之后,一定是播放到第2首。这个是确切的行为,如果不能实现,就是代码有bug了,需 要改正。终于可以扯到数据了。第2首是什么歌呢? 就是说第2首歌的内容是什么呢? 当然在程序员写代码的时候,他是不知道的,他要做的,就是预先开一片数据空间,以存放歌曲相关的数据。这片数据空间,想放什么就放什么,是灵活的。听烦了 这几首歌以后,再更换其它音频文件就是了。再说具体一点,程序就相当于修的一条路,让车可以在上面跑;但车上面装了什么,程序员是不知道的。

堆和栈属于数据存储区的范畴,也可以算是数据管理的手段或方法。基于此,不能一概而论,说哪个手段高明一些;他们也是基于现实的需要而产生的。黑格尔说:存在就是合理的。

这样的概念大家都不陌生:军队的管理是很严格的,很死板的;但是对于一些年轻的技术公司来说,员工就享有很高的自由度。

如果我说,墙角边整齐地摆放着10本书; 以及墙角边的书凌乱地放着。你闭上眼睛,能区分出两种画面吗? 如果没有,就不用往下看了。

栈的特性,就是严格/有序/规范的。栈的英文就是Stack. 如果我说,there are books stacked in that corner,你应该能知道书是怎么放的吧。

相反,堆呢,就是自由/灵活/随意的。堆的英文是Heap. 如果我说,there are books heaped in that corner,你应该能知道书是怎么放的吧。

二、get closer to the real STACK/HEAP。

栈: 由系统自动分配和回收的。

堆: 由程序员分配和回收的。

基于第一部分的理解,不用想都知道,作为“堆”的数据空间,也必须是灵活的,因为成千上万的程序员在写什么程序是未知的。但可知道的一点,就是他们是跑在确定的某个OS里面的。

因此,也不过就是给系统管理的数据空间起了个名字,就栈;给程序员使用的空间,起了个名,就堆。

我接下来就会废话:起什么名字都不重要,重要的是,我们得对这两种数据存储区的管理的机制由来,方法有深刻认识;这样,即便几个世纪以后它们更名为阿猫阿狗了,我们依然能认知它们。

举例:

void Check_Pro_Code( uint8 style )

{

uint8 i;

switch( style )

{

......

}

}

void main( )

{

uint8 j = 1;

Check_Pro_Code( j );

}

在main()函数里调用了Check_Pro_Code(...)函数,事先要对j进行入栈操作;当然这里函数调用的时候,涉及到几个入栈操作:程序的下一个执行地址;局部变量;形参。

这里,我就没有深入介绍了。

实在很惭愧的是,我写的嵌入式软件里,没有涉及到任何和堆操作相关的。我就是那样一个人,CM3内核里也没有移植操作系统,实在是汗颜,因为本人对RTOS实在是未曾涉猎。所以,我这里对于堆的介绍,是没有任何实战鹰眼的。并且为了堆我就堆了一下。你说,这样算学术造假吗?

void main( )

{

int j=10;

int *p;

p = malloc( 10 ); //话说这里就是堆,我是为了用而用,实在是无味地很。

p = "123456".

}

三、话说堆栈溢出

再次明确,堆栈溢出的堆栈是指栈。

1 当C程序函数的调用层次过深或者出现了递归调用,就容易使程序运行所需的堆栈空间超过系统能提供的最大堆栈空间范围,产生堆栈溢出。

这是很明白的,当A函数调用了B函数,而B()里面又调用了C(),C()里又调用了D()......当这样的调用太深的时候,就容易堆栈溢出了。

四、一级缓存/二级缓存

栈使用的是一级缓存, 他们通常都是被调用时处于存储空间中,调用完毕立即释放。

堆则是存放在二级缓存中,生命周期由虚拟机的垃圾回收算法来决定(并不是一旦成为孤儿对象就能被回收)。所以调用这些对象的速度要相对来得低一些。

栈的优势是,存取速度比堆要快,仅次于直接位于CPU中的寄存器

举个我知道的例子:

void main( )

{

int i,j;

static int flag = 1;

i = Sum_Of_Group( );

j = Check_Exist( );

}

这里,i,j的值都是给通用寄存器的,而不是给予确切的物理地址。而对于flag,由于其为静态变量,是在SRAM里面分配地址的。这里好像没有说到一级缓存二级缓存。时间限制,下回述。

五、栈:在Windows下,栈是向低地址扩展的数据 结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在 WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因 此,能从栈获得的空间较小。

堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。

注:该段内容100%抄袭,出处:网络。

六、如何修改我自己的工程的STACK(以下内容不通用)

由于我自己的工程用的是LPC1765,刚好从网络抄到了比较有用的图片。摘于此。其他单片机的编译环境,应该也是差不多如法炮制的。

编译环境: IAR for ARM.

图一 :如何修改STACK的大小

图二,如何知道自己的工程用了多少堆栈

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 堆栈
    +关注

    关注

    0

    文章

    184

    浏览量

    20592

原文标题:关于堆栈的深入理解

文章出处:【微信号:eet-china,微信公众号:电子工程专辑】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    关于FreeRTOS中断返回模式和堆栈指针的理解

    在学习RTOS的过程中,发现如下表格,即在中断或者异常处理函数中,r14返回EXC_RETURN: 以下是个人的浅显理解: 中断处理函数时,MCU进入handler模式,只能使用MSP指针。比如,当
    发表于 05-06 15:04

    深入理解单片机的位数对性能的影响

    单片机的位数是指其处理器核心的位宽,通常以比特(bit)为单位。常见的位数有8位、16位、32位和64位等。位数越高,处理器能够处理的数据量越大,性能也相应提高。以下是对单片机位数对性能影响的详细分析: 一、 数据处理能力 8位单片机:只能处理较小的整数范围,通常为0到255(即2^8 - 1)。这限制了它们的计算能力和适用范围,使其更适合简单的控制任务。 16位单片机:可以处理更大的整数范围,从0到65535(即2^16 - 1)。这使得它们能够执行更复杂的数学运算,如多精度算术和浮点数运算。 32位单片机:具有更大的整数处理能力,范围从0到4,294,967,295(即2^32 - 1),并且能够更高效地处理浮点数。这使得它们适合需要复杂数学运算的应用,如图像处理和科学计算。 64位单片机:提供极大的整数处理范围,从0到1.8446744e+19(即2^64 - 1),极大地扩展了数据操作的可能性。这对于需要处理大量数据的高性能计算应用尤为重要。 二、 内存容量 8位单片机:由于地址线数量有限,通常只能访问最多64KB的内存空间。这限制了程序和数据的大小,以及可运行的应用程序的复杂度。 16位单片机:能够访问更多内存,通常高达64MB,允许运行更大的程序并存储更多的数据。 32位单片机:提供高达4GB的内存访问能力,使得它们可以支持更大规模的软件项目和更复杂的数据结构。 64位单片机:理论上可以访问高达16EB(exabytes)的内存,虽然实际上受到物理内存大小的限制,但这样的设计为未来可能的需求提供了充足的空间。 三、指令集和效率 8位单片机:指令集相对简单,执行效率高,但由于数据宽度的限制,执行复杂算法时可能需要更多的指令和更长的执行时间。 16位单片机:拥有更丰富的指令集,可以更有效地执行复杂的逻辑和算术操作,提高了代码密度和执行速度。 32位单片机:指令集更为复杂和强大,支持高级语言特性,如直接支持浮点运算和向量操作,进一步提高了编程效率和运行速度。 64位单片机:提供最广泛的指令集,包括对大整数和高精度浮点数的原生支持,极大地提高了处理复杂计算任务的能力。 四、功耗和散热 8位单片机:通常功耗较低,因为它们的处理能力有限,不需要消耗太多能量来执行任务。这使得它们非常适合电池供电的设备和对能耗敏感的应用。 16位单片机:随着处理能力的提升,功耗也相应增加,但在许多情况下仍然保持了合理的能效比。 32位单片机:由于更高的处理能力和更大的内存访问需求,这些设备的功耗通常会更高。然而,现代技术的进步使得即使是32位设备也能在低功耗模式下有效运行。 64位单片机:虽然提供最高的性能,但也是能耗最大的。它们通常用于桌面计算机和服务器等不太在意功耗的应用中。 五、 成本 8位单片机:由于结构简单,制造成本低,是许多低成本应用的理想选择。 16位单片机:成本略高于8位单片机,但在性能上的提升往往能抵消成本的增加。 32位单片机:随着技术的发展,成本已经大幅下降,使得它们成为许多中高端应用的主流选择。 64位单片机:通常是最昂贵的,主要用于需要极高计算性能的场景,如高端服务器和超级计算机。 综上所述,单片机的位数对其性能有着显著的影响。选择合适的位数取决于应用的具体需求,包括数据处理能力、内存容量、功耗和成本等因素。在实际应用中,需要根据具体需求权衡这些因素,以获得最佳的性能和性价比。
    发表于 04-27 15:05

    怎么理解TCP三次握手和四次挥手

    作为运维工程师,无论是排查网络故障、分析日志,还是配置负载均衡器,都需要对 TCP 协议有深入理解。很多"疑难杂症"的根源,往往在于对 TCP 状态转换和连接管理理解不够透彻。
    的头像 发表于 04-10 16:42 835次阅读

    深入理解积分型ADC

    深入理解积分型ADC 一、引言 作为电子工程师,我们在设计中常常需要将模拟信号转换为数字信号,而积分型模数转换器(ADCs)就是实现这一功能的重要手段之一。积分型ADC能够提供高分辨率的模数转换,并
    的头像 发表于 04-02 09:15 748次阅读

    如何理解直流无刷电机倒相的说法?

    直流无刷电机(BLDC)的“倒相”是电机控制领域的关键概念,其本质是通过电子换相替代传统有刷电机的机械换相,实现高效、精准的转矩控制。要深入理解这一说法,需从工作原理、控制逻辑及技术实现三个维度展开分析。
    的头像 发表于 03-16 17:31 709次阅读

    怎样理解和调试变频器的转矩提升功能

    变频器作为现代工业控制中不可或缺的核心设备,其转矩提升功能直接关系到电机启动性能、负载适应能力以及系统能效优化。这一功能的合理设置,既是工程师调试经验的体现,也是实现设备高效运行的关键技术环节。要深入理解转矩提升的本质,需从原理出发,结合应用场景,掌握其调试方法论。
    的头像 发表于 02-28 16:57 713次阅读
    怎样<b class='flag-5'>理解</b>和调试变频器的转矩提升功能

    关于步进电机脉冲和步距角相关的问题

    步进电机作为一种将电脉冲信号转换为角位移或线位移的执行元件,其核心控制参数——脉冲与步距角的关系直接决定了系统的精度与动态性能。要深入理解这一机制,需从步进电机的工作原理、脉冲驱动特性、步距角内涵以及实际应用中的关键考量展开分析。
    的头像 发表于 02-27 16:49 653次阅读
    <b class='flag-5'>关于</b>步进电机脉冲和步距角相关的问题

    深入剖析LTC6813 - 1:多节电池堆栈监测的理想选择

    深入剖析LTC6813 - 1:多节电池堆栈监测的理想选择 作为一名电子工程师,在设计电池管理系统时,高效、精确的电池监测芯片至关重要。今天,咱们就来深入探讨一款优秀的电池监测芯片——LTC6813
    的头像 发表于 02-24 11:10 388次阅读

    深入剖析LTC6810-1/LTC6810-2:6通道电池堆栈监控器的卓越之选

    深入剖析LTC6810-1/LTC6810-2:6通道电池堆栈监控器的卓越之选 在电子工程师的日常工作中,电池管理系统的设计至关重要,而一款优秀的电池堆栈监控器能为系统的稳定性和可靠性提供有
    的头像 发表于 02-12 16:45 2556次阅读

    在学单片机时在堆栈遇到的问题分享

    一个堆栈溢出时会偶然产生坏的事情,你可以使用堆栈检查函数检测溢出情况 。 关于堆栈检查函数: 启动代码在硬件堆栈和软件
    发表于 01-23 07:47

    【「Linux 设备驱动开发(第 2 版)」阅读体验】+读深入理解Linux内核内存分配

    时复用”,在fork()系统调用中广泛使用;中断上下文中发生的缺页中断会导致双重故障中断,通常会使内核崩溃等。经过这段时间的阅读,收获颇丰,此书有不少关于内核开发的新内容值得本人深入学习借鉴。感谢电子发烧友平台提供的评阅机会。
    发表于 01-16 20:05

    深入理解分布式共识算法 Raft

    “不可靠的网络”、“不稳定的时钟”和“节点的故障”都是在分布式系统中常见的问题,在文章开始前,我们先来看一下:如果在分布式系统中网络不可靠会发生什么样的问题。 有以下 3 个服务构成的分布式集群,并在 server_1 中发生写请求变更 A = 1,“正常情况下” server_1 将 A 值同步给 server_2 和 server_3,保证集群的数据一致性: 但是如果在数据变更时发生网络问题(延迟、断连和丢包等)便会出现以下情况:比如有两个写操作同时发生在 server_1 或
    的头像 发表于 11-27 14:51 476次阅读
    <b class='flag-5'>深入理解</b>分布式共识算法 Raft

    堆栈的定义,堆栈的使用方法

    堆栈的定义 堆栈也是用户使用的存储器的一部分,用于存放临时性的数据和一些其他信息。堆栈段的定义语法如下: 堆栈名SEGMENTSTACK (
    发表于 11-21 06:49

    关于“实时基准对比测量”与AI再探讨

    他们又提到“还想多问一句”,说明他们对这个方案还有疑虑或者想深入理解某些细节。 用户可能是硬件工程师或者系统设计师,正在设计一个高精度的测量系统,面临模拟增益控制带来的稳定性挑战。他们的真实需求不仅是解决当前问题,可能还希望确保方案可行性,避免后期
    的头像 发表于 10-14 17:39 670次阅读

    深入理解PTP:高精度时间同步的核心原理

    PTP实现高精度的核心在于其精密的测量机制和对网络延迟的细致处理。我们以常见的端到端 (End-to-End, E2E) 延迟请求-响应机制为例,来剖析PTP的“对表”艺术。
    的头像 发表于 09-01 17:41 2568次阅读
    <b class='flag-5'>深入理解</b>PTP:高精度时间同步的核心原理