扫盲回帖系列之1——栈的疑问

       看到一个提问帖子(http://bbs.csdn.net/topics/390930552),问题摘录如下:

--------------------------------------------------------------------------------

例如函数调用的时候会在栈中为函数开辟一段空间,函数的参数也会挨个入栈,函数调用结束,会平衡栈,释放空间。
函数的局部变量也会压入栈中。
这里说的栈,应该是不是数据结构中的栈吧?指的是操作系统在内存中的一段区域?
经常会看到这么一句话“栈由系统自动分配,速度较快。”那么,
为什么操作系统或者开发操作系统的人要选择使用栈来管理呢?为什么不使用其他方式(数据结构?)?
是因为栈是向下扩展,利于判断是否溢出吗? 有没有别的理由?

--------------------------------------------------------------------------------------

        直觉印象:涉及到基本概念!但平时并没有对这些基本概念进行整理,所以要回答真要组织思路。蜻蜓点水似的回答对自己和别人都未必负责。说不定贴主的疑问恰恰就是来自一些比较模糊或似是而非说明导致的。所以看起来贴主是一个喜欢认真思考的人,尽管从贴主提的问题之间的逻辑连贯性来看,还有些混沌。

        正因为贴主的问题的混沌特点,我只能自行揣摩贴主真正的疑问,并整理一下,按我自己的思路来回答。

        首先,栈并不一定意味着向下扩展,也有向上扩展的栈。

        其次:实际上,就单个函数而言,函数参数以及局部变量放在栈中,并不主要是利用栈的后进先出的特点。函数参数以及局部变量(注意其实是局部自动变量,不包括局部静态变量,尽管局部静态变量大小也是固定的)最大的特点是编译时占用空间的确定性,因为确定,所以编译器(注意这里是编译器,不是模糊的“系统”)可以帮程序员来管理(或者说维护)这些空间,而且这种管理(或维护)的成本很低,基本上简单操纵栈指针就能实现。但是,设想一个任务或线程运行时的动态图景:主函数A调用B函数,B调用C函数,C函数返回到B,B再调用D函数……,这个动态调用链路上的每个函数的“活动记录”(就是前面提到的该函数的参数及局部变量),确符合标准的数据结构栈定义特点:C函数的活动记录作为最后入栈的,须先出(释放),然后才谈得上访问更早入栈的B函数的活动记录,道理以此类推。

        第三,如前面“其次”中提到的,栈的管理或者说栈的使用、维护者其实是编译器(为讨论简化,不考虑手工使用栈的汇编程序情形)。对操作系统而言,主要是在任务或线程的初始化期间,初始化栈的指针,如果CPU硬件提供足够支持,操作系统也能捕获栈的溢出,若真的捕获到,一般操作系统认为这是一个任务或线程自身并未意识到的重大错误,并极有可能终止任务或线程的执行,此终止行为基本上是不受任务或线程自身控制的。与此相对的是,堆空间一般很大,即使用光,任务或线程一般自己知道,所以会在任务或线程控制下选择妥善的方式来处理这个问题。

        第四,编程实用建议。一般来说,由于任务或线程的函数调用链条并不太长(层次很深的递归函数调用除外),并且函数活动记录并不大的特点,一个任务或线程的栈空间是不大的。所以建议在栈上不要放置大的数组(即声明很大的局部数组变量),否则:幸运的话是编译器会提示你,不幸运的话,造成堆栈溢出运行时遭操作系统强行终止,或者更不幸,操作系统不能检测到堆栈溢出,导致程序运行出现奇怪的错误。关于堆栈大小多说两句:一般任务或线程的堆栈大小是可以由程序初始化时来设置,包含线程的进程的总堆栈大小一般也可以在链接时指定,但这些设定都是在应用发布给客户前就固化了下来,所以基本上不要指望客户拿到你的应用之后根据实际情况来调整堆栈大小(尽管理论上客户是有办法修改堆栈空间大小),本质上,堆栈大小是一个应该由开发人员在应用发布之前(经内部测试来)确定的事情。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值