局部变量与栈

来源:百度文库 编辑:神马文学网 时间:2024/04/29 22:06:25
程序运行的时候是把局部变量放在栈区,而动态变量放在堆区。请大家详细解释下这样安排的原因是啥?可以把局部变量放在堆区吗?为社么?谢谢 
--------------------------------------------------------------- 

栈区是普通的栈数据结构,遵循LIFO后进先出的规则,局部变量安排在那里是ASM时就规定的,这样可以在一个函数结束后平衡堆栈,操作简单,效率高 
堆(动态区)在这里应当叫堆栈(不要和数据结构中的堆搞混)是程序在编译时产生的一块用于产生动态内存分配使用的块,操作比较栈要麻烦许多,在分配时要判断最优的地址(防止产生无用的内存碎片(由于屡次的NEW和DELETE产生的夹在两块使用中内存中的空余小内存(不容易被分配))),分配和回收时的效率比栈低多了 
--------------------------------------------------------------- 

栈是系统提供的功能,特点是快速高效,缺点是有限制,数据不灵活;而栈是函数库提供的功能,特点是灵活方便,数据适应面广泛,但是效率 >有一定降低。栈是系统数据结构,对于进程/线程是唯一的;堆是函数库内部数据结构,不一定唯一。不同堆分配的内存无法互相操作。栈空间分静态分配和动态分配两种。静态分配是编译器完成的,比如自动变量(auto)的分配。动态分配由alloca函数完成。栈的动态分配无需释放(是自动的),也就没有释放函数。为可移植>的程序起见,栈的动态分配操作是不被鼓励的!堆空间的分配总是动态的,虽然程序结束时所有的数据空间都会被释放回系统,但是精确的申请内存/ 释放内存匹>配是良好程序的基本要素。 
这是我对堆与栈收藏内容~ 
--------------------------------------------------------------- 

哦,不行的。 
如果所有局部变量都在堆上分配,那么每次函数调用都要增加一次malloc和free,本来一次指针加法和一次指针加法就可以搞定的事情就一下子变得低效了不下10倍。 
但问题在于,现在你要调用函数了,你需要首先调用malloc,为被调函数分配存储空间(或者被调函数自己调用malloc来为自己分配,都一样),然后函数返回的时候调用free。 
好了,函数调用开始了,首先malloc被调用,但malloc也是函数啊,为了调用函数,你首先要调用谁?当然是malloc,好,再调用malloc,但malloc也是函数啊,为了调用函数,你首先要调用谁?当然是malloc,好,再调用malloc,…… 

这就叫无限递归。。。。 
--------------------------------------------------------------- 

一般将全局变量存放在数据区,局部变量存放在栈区, 
动态变量存放在堆区,函数代码放在代码区。 
--------------------------------------------------------------- 

堆是程序员管理的,栈是系统管理的. 
--------------------------------------------------------------- 

局部变量放在栈区,而动态变量放在堆区。请大家详细解释下这样安排的原因是啥? 
---------- 
局部变量是有确定生命期的,这个可以由系统来管理(事实也是如此),而系统管理的是栈,所以,局部变量在栈中; 
动态变量的生命期由程序员决定,所以要放在堆中。 
(也许,注意,是也许,原始的设计的原因是为了 便于程序的设计 和 管理(否则一切事物都要程序员来解决,会累死人的)) 

可以把局部变量放在堆区吗? 
----------------------- 
怎么说呢?   所有的编译器都不可能达到这样的效果。 

如果你非要这样,哎 ,可以自己发明一种语言,自己设计编译器,要圆要扁,还不是你自己决定? 呵呵 ! 
--------------------------------------------------------------- 

Java中的内建类型和对象的引用也是放在栈里边的,这也是不够成无限递归的原因。 
其实只要你愿意,你也可以按Java风格写C++程序:每个局部变量都通过new动态产生,然后变量本身自然在堆里,指向它的指针则在栈里。只是别忘了delete。 
总之,不可能所有的东西都放堆里。 
--------------------------------------------------------------- 

steedhorse(晨星) 说的那个无限递归很有道理哦。。 
--------------------------------------------------------------- 

真是这样的吗?! 

我怎么觉得大家都没说到点子上,甚至连堆和栈是什么都没能讲清楚。 

看下边的代码 

class Test { 
  public static void main(String[] args) { 
    Obj obj = new Obj(); 
    obj.do(); 
  } 


class Obj { 
  public do() { 
    int i = 0; 
  } 


思考题: 
1、i 做为 obj 的一个成员,是不是在堆中? 
2、当主线程执行 obj.do() 时,i 是不是在主线程的栈上? 

:) 

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

(1)obj这个对象在堆中,但栈中保存着它的引用,否则如果没有东西引用它,这个对象会被垃圾回收器收掉的。 
(2)i是在栈上。 
关于函数栈,学过编译原理会更清楚一些。 
--------------------------------------------------------------- 

任何一门语言或者编译器,如果想把所有的局部变量(包括局部产生的对象和这些对象的引用、指针等、别名等)都放到堆上去,就只能在每次函数调用前首先分配堆空间。 
--------------------------------------------------------------- 

我是说:假如要实现楼主的愿望:“函数调用时所有的局部东西都放堆里,半点也不留在栈里”,那么函数调用就必然造成无限递归。 

并非说平时我们的函数调用都会造成无限递归。一般的编译器都把局部变量(或者至少它们的引用)放在栈里,当然不会造成无限递归。 
--------------------------------------------------------------- 

当然,如果你说:“假如所有的函数都用堆,只有malloc不用堆”,那malloc用啥?只用栈?全部函数都被不用栈,就单单为了malloc这一个函数(当然,还有其它几个)来开辟一个栈并开发一套栈式调用算法?那不是很蹩脚么? 
那么C编译器在编译运行时库的时候,每次编译到一个函数,都得检查一下,这个函数的名字是否叫做“malloc”(或者“realloc”等几个),如果是就做特殊处理,如过不叫malloc就做一般处理? 

不用往下说了,这样的编译器听起来不觉的别扭吗? 
--------------------------------------------------------------- 

可能我说得太多了吧。其实问题本来很简单,关键就在于:如果你想放弃使用栈,而统一使用堆来进行一切函数调用,那么就不能再使用简单的栈指针加减来进行栈内存的分配,而必须在每个函数被调用前为函数动态分配保存局部变量的空间,但分配空间的函数也是函数,它也得首先调用它自己来分配空间,于是形成了无限递归。 
--------------------------------------------------------------- 

局部变量不是全部放于栈的,关键看自己如何定义。 

   而关于堆和栈,真的是各有所用,各有各的特点。虽然大家都是位于RAM中。 
   对于栈,cpu经由其stack pointer 提供直接支援。编译器必须能够完全掌握变量(对象)的大小和存活时间。优点是存取较快,不需要自行回收空间。 
   而对于堆,编译器不需要知道变量(对象)的大小及其存活多久。相比栈,存取较慢,空间需要自行释放,否则会造成臭名昭著的“Menory leading”。 

   其实,变量的存储空间除了栈和堆,还有cpu暂存器(Registers)、静态储存空间(Static storage)、常量储存空间(Constant storage)、Non RAM储存空间。它们都是各有各的用途,各有各的特点。 
--------------------------------------------------------------- 

呵呵,不好意思,把大家搞糊涂了。一些话说的不严密,尤其这句容易误导: 
“如果你想放弃使用栈,而统一使用堆来进行一切函数调用,那么就不能再使用简单的栈指针加减来进行栈内存的分配,而必须在每个函数被调用前为函数动态分配保存局部变量的空间,……” 
应该改成: