C++中堆和栈的区别

上传人:re****.1 文档编号:457922282 上传时间:2023-11-24 格式:DOCX 页数:5 大小:14.43KB
返回 下载 相关 举报
C++中堆和栈的区别_第1页
第1页 / 共5页
C++中堆和栈的区别_第2页
第2页 / 共5页
C++中堆和栈的区别_第3页
第3页 / 共5页
C++中堆和栈的区别_第4页
第4页 / 共5页
C++中堆和栈的区别_第5页
第5页 / 共5页
亲,该文档总共5页,全部预览完了,如果喜欢就下载吧!
资源描述

《C++中堆和栈的区别》由会员分享,可在线阅读,更多相关《C++中堆和栈的区别(5页珍藏版)》请在金锄头文库上搜索。

1、C+常识之一一C+中堆和栈的区别,自由存储区、全局/静态存储区和常量存储区在C+中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存 储区。栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区。里面 的变量通常是局部变量、函数参数等。堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制 一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会 自动回收.自由存储区,就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free 来结束自己的生命的.全局/静态存储区,全局变量和

2、静态变量被分配到同一块内存中,在以前的C语言中,全局 变量又分为初始化的和未初始化的(初始化的全局变量和静态变量在一块区域,未初始化的 全局变量与静态变量在相邻的另一块区域,同时未被初始化的对象存储区可以通过void*来 访问和操纵,程序结束后由系统自行释放),在C+里面没有这个区分了,他们共同占用同一 块内存区。常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改(当然,你 要通过非正当手段也可以修改,而且方法很多)明确区分堆与栈在bbs上,堆与栈的区分问题,似乎是一个永恒的话题,由此可见,初学者对此往往是混淆不清 的,所以我决定拿他第一个开刀。首先,我们举一个例子:voi

3、d f() int大 p=new int 5; 这条短短的一句话就包含了堆与栈,看到new,我们首先就应该想到,我们分配了一块堆内 存,那么指针p呢?他分配的是一块栈内存,所以这句话的意思就是:在栈内存中存放了一 个指向一块堆内存的指针p。在程序会先确定在堆中分配内存的大小,然后调用operator new 分配内存,然后返回这块内存的首地址,放入栈中,他在VC6下的汇编代码如下: 00401028 push 14h0040102A call operator new (00401060)0040102F add esp,400401032 mov dword ptr ebp-8,eax004

4、01035 mov eax, dword ptr ebp800401038 mov dword ptr ebp4 ,eax这里,我们为了简单并没有释放内存,那么该怎么去释放呢?是delete p么?澳,错了,应 该是delete p,这是为了告诉编译器:我删除的是一个数组,VC6就会根据相应的Cookie 信息去进行释放内存的工作。好了,我们回到我们的主题:堆和栈究竟有什么区别?主要的区别由以下几点:1、管理方式不同;2、空间大小不同;3、能否产生碎片不同;4、生长方向不同;5、分配方式不同;6、分配效率不同;管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作 由

5、程序员控制,容易产生memory leak。空间大小:一般来讲在32位系统下,堆内存可以达到4G的空间,从这个角度来看堆内存几乎 是没有什么限制的。但是对于栈来讲,一般都是有一定的空间大小的例如,在VC6下面,默 认的栈空间大小是1M (好像是,记不清楚了).当然,我们可以修改:打开工程,依次操作菜单如下:Project-Setting-Link,在Category中选中Output,然后在 Reserve中设定堆栈的最大值和commit。注意:reserve最小值为4Byte; commit是保留在虚拟内存的页文件里面,它设置的较大会使 栈开辟较大的值,可能增加内存的开销和启动时间。碎片问题

6、:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎 片,使程序效率降低.对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是 如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出,在他弹出之前,在他上 面的后进的栈内容已经被弹出,详细的可以参考数据结构,这里我们就不再一一讨论了。 生长方向:对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;对于栈来讲, 它的生长方向是向下的,是向着内存地址减小的方向增长。分配方式:堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配. 静态分配是编译器完成的,比如局部变量的分配。动

7、态分配由alloca函数进行分配,但是栈 的动态分配和堆是不同的,他的动态分配是由编译器进行释放无需我们手工实现。分配效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器 存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高.堆则是C/C+ 函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具 体的算法可以参考数据结构/操作系统)在堆内存中搜索可用的足够大小的空间如果没有足 够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存 空间,这样就有机会分到足够大小的内存,然后进行返回。显然,堆的效率比

8、栈要低得多。 从这里我们可以看到,堆和栈相比,由于大量new/delete的使用,容易造成大量的内存碎 片;由于没有专门的系统支持,效率很低;由于可能引发用户态和核心态的切换,内存的申 请,代价变得更加昂贵。所以栈在程序中是应用最广泛的,就算是函数的调用也利用栈去完 成,函数调用过程中的参数,返回地址,EBP和局部变量都采用栈的方式存放.所以,我们推 荐大家尽量用栈,而不是用堆。虽然栈有如此众多的好处,但是由于和堆相比不是那么灵活,有时候分配大量的内存空间, 还是用堆好一些。无论是堆还是栈,都要防止越界现象的发生(除非你是故意使其越界),因为越界的结果要 么是程序崩溃,要么是摧毁程序的堆、栈结

9、构,产生以想不到的结果,就算是在你的程序运 行过程中,没有发生上面的问题,你还是要小心,说不定什么时候就崩掉,那时候debug可 是相当困难的:)对了,还有一件事,如果有人把堆栈合起来说,那它的意思是栈,可不是堆,呵呵,清楚了?static用来控制变量的存储方式和可见性函数内部定义的变量,在程序执行到它的定义处时,编译器为它在栈上分配空间,函数在栈 上分配的空间在此函数执行结束时会释放掉,这样就产生了一个问题:如果想将函数中此变 量的值保存至下一次调用时,如何实现?最容易想到的方法是定义一个全局的变量,但定 义为一个全局变量有许多缺点,最明显的缺点是破坏了此变量的访问范围(使得在此函数中 定义

10、的变量,不仅仅受此函数控制)。需要一个数据对象为整个类而非某个对象服务,同时又力求不破坏类的封装性,即要求此成员 隐藏在类的内部,对外不可见。static的内部机制:静态数据成员要在程序一开始运行时就必须存在。因为函数在程序运行中被调用,所以静态 数据成员不能在任何函数内分配空间和初始化。这样,它的空间分配有三个可能的地方,一 是作为类的外部接口的头文件,那里有类声明;二是类定义的内部实现,那里有类的成员函 数定义;三是应用程序的main()函数前的全局数据声明和定义处。静态数据成员要实际地分配空间,故不能在类的声明中定义(只能声明数据成员)。类声明 只声明一个类的“尺寸和规格”,并不进行实际

11、的内存分配,所以在类声明中写成定义是错误 的。它也不能在头文件中类声明的外部定义,因为那会造成在多个使用该类的源文件中,对 其重复定义。static被引入以告知编译器,将变量存储在程序的静态存储区而非栈上空间静态数据成员按定义出现的先后顺序依次初始化,注意静态成员嵌套时,要保证所嵌套的成员已 经初始化了。消除时的顺序是初始化的反顺序。static的优势:可以节省内存,因为它是所有对象所公有的,因此,对多个对象来说,静态数据成员只存储一 处,供所有对象共用.静态数据成员的值对每个对象都是一样,但它的值是可以更新的。只要 对静态数据成员的值更新一次,保证所有对象存取更新后的相同的值,这样可以提高时

12、间效 率。引用静态数据成员时,采用如下格式:类名 : 静态成员名如果静态数据成员的访问权限允许的话(即public的成员),可在程序中,按上述格式 来引用静态数据成员。ps:(1)类的静态成员函数是属于整个类而非类的对象,所以它没有this指针,这就导致了它 仅能访问类的静态数据和静态成员函数。不能将静态成员函数定义为虚函数。(3)由于静态成员声明于类中,操作于其外,所以对其取地址操作,就多少有些特殊,变量地 址是指向其数据类型的指针,函数地址类型是一个“nonmember函数指针”.(4)由于静态成员函数没有this指针,所以就差不多等同于nonmember函数,结果就产生了 一个意想不到的

13、好处:成为一个callback函数,使得我们得以将c+和c-based x window系 统结合,同时也成功的应用于线程函数身上。(5)static并没有增加程序的时空开销,相反她还缩短了子类对父类静态成员的访问时间, 节省了子类的内存空间。(6)静态数据成员在定义或说明时前面加关键字static。(7)静态数据成员是静态存储的,所以必须对它进行初始化。(8)静态成员初始化与一般数据成员初始化不同:初始化在类体外进行,而前面不加static,以免与一般静态变量或对象相混淆;初始化时不加该成员的访问权限控制符private,public等;初始化时使用作用域运算符来标明它所属类;所以我们得出静

14、态数据成员初始化的格式:数据类型类名:静态数据成员名=值(9)为了防止父类的影响,可以在子类定义一个与父类相同的静态变量,以屏蔽父类的影响。这里有一点需要注意:我们说静态成员为父类和子类共享,但我们有 重复定义了静态成员, 这会不会引起错误呢?不会,我们的编译器采用了一种绝妙的手法:name-mangling用以生 成唯一的标志。【转】全局变量静态变量static声明的变量在C语言中有两方面的特征:1)、变量会被放在程序的全局存储区中,这样可以在下一次调用的时候还可以保持原来 的赋值。这一点是它与堆栈变量和堆变量的区别。2)、变量用static告知编译器,自己仅仅在变量的作用范围内可见。这一点

15、是它与全局 变量的区别。Tips:A. 若全局变量仅在单个C文件中访问,则可以将这个变量修改为静态全局变量以降低 模块间的耦合度;B. 若全局变量仅由单个函数访问,则可以将这个变量改为该函数的静态局部变量,以降 低模块间的耦合度;C. 设计和使用访问动态全局变量、静态全局变量、静态局部变量的函数时,需要考虑重入 问题;D. 如果我们需要一个可重入的函数,那么,我们一定要避免函数中使用static变量(这样的 函数被称为:带“内部存储器”功能的的函数)E。函数中必须要使用static变量情况:比如当某函数的返回值为指针类型时,则必须是static 的局部变量的地址作为返回值,若为auto类型,则返回为错指针。函数前加static使得函数成为静态函数.但此处“static的含义不是指存储方式,而是指对函数 的作用域仅局限于本文件(所以又称内部函数)。使用内部函数的好处是:不同的人编写不同 的函数时,不用担心自己定义的函数是否会与其它文件中的函数同名。扩展分析:术语static有着不寻常的历史。起初,在C中引入关键字static是为了表示退出 一个块后仍然存在的局部变量。随后,static在C中有了第二种含义:用来表示不能被其它文件 访问的全局变量和函数。为了避免引入新的关键字,所以仍使用static关键字来表示这第二 种含义。最后,C+重用了这个关键字,并赋予它与前面不同

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 学术论文 > 其它学术论文

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号