分类: C/C++
2009-05-30 17:49:42
堆和栈的区别二:
堆:
是大家共有的空间,分全局堆和局部堆。全局堆就是所有没有分配的空
间,局部堆就是用户分配的空间。堆在操作系统对进程 初始化的时候分配,运
行过程中也可以向系统要额外的堆,但是记得用完了要还给操作系统,要不然就
是内存泄漏。堆里面一般 放的是静态数据,比如 Static的数据和字符
串常量等,资源加载后一般也放在堆里面。一个进程的所有线程共有这些堆 ,
所以对堆的操作要考虑同步和互斥的问题。程序里面编译后的数据段都是堆的一
部分。
栈:
是个线程独有的,保存其运行状态和局部自动变量的。栈在线程开始的时
候初始化,每个线程的栈互相独立,因此 ,栈是 thread safe的。每个C ++对象的数据成员也存在在栈中,每个函数都有自己的栈,栈被用来在函数 之
间传递参数。操作系统在切换线程的时候会自动的切换栈,就是切换 SS/E
SP寄存器。栈空间不需要在高级语言里面显式的分配 和释放。
1、管理方式不同;
管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生memory
leak。
2、空间大小不同;
3、能否产生碎片不同;
碎片问题:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲
,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出,在他
弹出之前,在他上面的后进的栈内容已经被弹出,详细的可以参考数据结构,这里我们就不再一一讨论了。
4、生长方向不同;
生长方向:对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;对于栈来讲,它的生长方向是向下的,是向着
内存地址减小的方向增长。
5、分配方式不同;
6、分配效率不同;
分配效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专
门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会
按照一定的算法(具体的算法可以参考数据结构/操作系统)在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可
能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后进行返回
。显然,堆的效率比栈要低得多。
从这里我们可以看到,堆和栈相比,由于大量new/delete的使用,容易造成大量的内存碎片;由于没有专门的系统支持,效率很
低;由于可能引发用户态和核心态的切换,内存的申请,代价变得更加昂贵。所以栈在程序中是应用最广泛的,就算是函数的调用也
利用栈去完成,函数调用过程中的参数,返回地址,EBP和局部变量都采用栈的方式存放。所以,我们推荐大家尽量用栈,而不是用
堆。
虽然栈有如此众多的好处,但是由于和堆相比不是那么灵活,有时候分配大量的内存空间,还是用堆好一些。
对了,还有一件事,如果有人把堆栈合起来说,那它的意思是栈,可不是堆,呵呵,清楚了?
引用一网上的解释:
栈是由cpu实现的一种数据结构,其特点是后进先出。用于程序局部变量、程序返回地址。调用子程序、声明局部变量时,实际上就是在告诉编译程序使用“栈”这种数据结构。程序链接(link.exe)时,必须告诉链接程序为进程保留多大的栈空间。进程被加载时,操作系统就为该进程分配或者说保留这么大的内存空间作为栈来使用。
代码空间、栈空间、全局变量空间都是保留的,没有这些空间进程会加载失败。这个时候操作系统会提示系统内存太少无法加载进程。
堆空间相对代码空间、栈空间、全局变量空间,它是没娘的孩子。因为系统除去这些保留的空间,剩下的都是自由空间,它的头上插了根草标,表示这些空间没有使用,谁都可以自由的使用。
堆空间唯一有用的时候,就是你的程序在执行malloc、realloc、new等操作时,堆空间就像站街女等待你的挑选。不过,操作系统的眼光好一点,它会通过malloc等函数帮你选好合适的站街女,选好的站街女就是这几个函数的返回值。
站街女用完了之后,就用free、delete等操作撵走。
- 再通俗一点来说,栈是已经预先保留的内存空间,必须按照后进先出的方法使用。
- 而堆是,进程加载之后,系统多余的空间。
如果程序加载时,操作系统提示内存不够导致加载失败,则必须去电脑城买一条更大的内存。
如果程序运行过程中,提示栈溢出,则必须告诉程序员,重新链接程序。链接程序时指定大一点的栈空间。
如果程序运行过程中,提示内存不够,这意味着堆空间不够。也必须去电脑城买一条更大的内存。
如果不想买内存,或许可以这样:关闭一些已经运行的程序。比如防火墙、杀毒软件等,游戏、realplay、winamp就别关了。电脑不娱乐,还有什么用呀^_^。
补充一点:之所以要告诉链接程序需要保留多大的栈空间,是因为,无论是编译程序还是链接程序,都不知道程序运行需要多少栈空间,其实连程序员自己也不知道,只不过是根据经验指定。不过实际写程序时,好像大家并没有做这个操作,是因为开发平台有一个默认值已经设置好了。
而代码空间和全局变量空间不一样,程序编译好了就知道需要多大的代码空间和全局变量空间。所以链接程序可以自己决定。
堆和栈的区别三:
堆(heap)和栈(stack)是C/C++编程不可避免会碰到的两个基本概念。首先,这两个概念都可以在讲数据 结构的书中找到,他们都是基本的数据结构,虽然栈更为简单一些。 在具体的C/C++编程框架中,这两个概念并不是并行的。对底层机器代码的研究可以揭示,栈是机器系 统提供的数据结构,而堆则是C/C++函数库提供的。 具体地说,现代计算机(串行执行机制),都直接在代码底层支持栈的数据结构。这体现在,有专门的寄 存器指向栈所在的地址,有专门的机器指令完成数据入栈出栈的操作。这种机制的特点是效率高,支持的数据有限,一般是整数,指针,浮点数等系统直接支持的数据类型,并不直接支持其他的数据结构。因为栈的这种特点,对栈的使用在程序中是非常频繁的。对子程序的调用就是直接利用栈完成的。机器的call指令里隐含了把返回地址推入栈,然后跳转至子程序地址的操作,而子程序中的ret指令则隐含从堆栈中弹出返回地址并跳转之的操作。C/C++中的自动变量是直接利用栈的例子,这也就是为什么当函数返回时,该函数的自动变量自动失效的原因。
和栈不同,堆的数据结构并不是由系统(无论是机器系统还是操作系统)支持的,而是由函数库提供的。
基本的malloc/realloc/free函数维护了一套内部的堆数据结构。当程序使用这些函数去获得新的内存空间时,这套函数首先试图从内部堆中寻找可用的内存空间,如果没有可以使用的内存空间,则试图利用系统调用来动态增加程序数据段的内存大小,新分配得到的空间首先被组织进内部堆中去,然后再以适当的形式返回给调用者。当程序释放分配的内存空间时,这片内存空间被返回内部堆结构中,可能会被适当的处理(比如和其他空闲空间合并成更大的空闲空间),以更适合下一次内存分配申请。这套复杂的分配机制实际上相当于一个内存分配的缓冲池(Cache),使用这套机制有如下若干原因:
1. 系统调用可能不支持任意大小的内存分配。有些系统的系统调用只支持固定大小及其倍数的内存请求(按页分配);这样的话对于大量的小内存分类来说会造成浪费。
2. 系统调用申请内存可能是代价昂贵的。系统调用可能涉及用户态和核心态的转换。
3. 没有管理的内存分配在大量复杂内存的分配释放操作下很容易造成内存碎片。
堆和栈的对比
从以上知识可知,栈是系统提供的功能,特点是快速高效,缺点是有限制,数据不灵活;而栈是函数库提供的功能,特点是灵活方便,数据适应面广泛,但是效率有一定降低。栈是系统数据结构,对于进程/线程是唯一的;堆是函数库内部数据结构,不一定唯一。不同堆分配的内存无法互相操作。栈空间分静态分配和动态分配两种。静态分配是编译器完成的,比如自动变量(auto)的分配。动态分配由
alloca函数完成。栈的动态分配无需释放(是自动的),也就没有释放函数。为可移植的程序起见,栈的动态分配操作是不被鼓励的!堆空间的分配总是动态的,虽然程序结束时所有的数据空间都会被释放回系统,但是精确的申请内存/释放内存匹配是良好程序的基本要素。
可以放一块思考
堆和栈的生长方向恰好相反,
|--------------| 低地址
| 堆 |
|--------------|
| | |
| I |
| |
| ^ |
| 栈 | 高地址
-----------------
所以计算机中的堆和栈经常时放一块讲的
nod 一般不是必要就不要动态创建,最讨厌把new出来的东西当局部变量用,用万了马上
delete 的做法.
理由
1.栈分配比堆快,只需要一条指令就呢给配所有的局部变量
2.栈不会出现内存碎片
3。栈对象好管理
当然,某些情况下也要那么写,比如
1.对象很大
2.对象需要在某个特定的时刻构造或析够
3.类只允许对象动态创建,比如VCL的大多数类
当然,必须用堆对象时也不能躲避。
以上内容转载:
http://www.cnblogs.com/Fancyboy2004/archive/2009/02/17/1392603.html
http://blog.csdn.net/iori_guojun/archive/2005/12/07/546013.aspx