版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
内存分为代码区、全局数据区、堆区和栈区。堆一般存放动态数据,栈里一般存放局
部成员。
关于堆栈和堆的概念
[问题]
C++中创建本地(或者说局域)变量是在堆栈(stack)中安排内存地址,而创建全
局变量则是在堆(heap)中安排内存地址。我想知道什么是堆(heap)?为什么全局变
量和本地变量在安排内存地址时要分别对待,堆和堆栈哪一个更有效率?
[回答]
在Window中执行的每一个应用程序都有其自己的内存地址。一部分内存空间用于存
放程序代码,一部分内存空间用于存放程序执行期间创建的变量。创将变量的方法有两种,
一种是在堆中,此外一种则在堆栈里。
理解堆的最好的方法是将它看成一个程序随时可以使用的内存块。为了创建堆变量,
程序要使用"new”(在C++里)操作符或者"malloc”(在C中)例程,它们返回指向
变量的指针(堆变量总是通过指针来处理和操作\最终程序用“delete”(在C++里)操
作符成者"free"(在C中)例程来删除或者释放内存空间.
而堆栈则不同,它是某个函数被调用后随时可以创建的一小块内存,被用于在函数范
围内保存变量(也称为自动变量1在函数中,任何包含在。内的代码都有其自己的堆栈。
当这个函数或者{}退出时,堆栈以及它包含的全部内容都被摧毁。因此下面的代码是不运
行的:
voidMyfunction()
(
inti=5;
(
intj=6;
)
intk=i+j;
)
所以本文问题的答案是:使用堆栈(stack)安排本地或者局域变量的地址空间,而用
堆(heap)安排大块内存地址或者动态创建对象的情形。
例如:
voidMyFunctionQ
int5;//堆栈中的本地(自动)变量
int*iArray;//堆栈中的本地(自动)变量
iArray=newint[10000);//这一行代码将在堆中创建10000个元
素的数组,由iArray指向其地址
for(inik=0,k<10000;k十十)
(
iArray[k]=k+i;
cout<<iArray[k]<<"\n";
)
deleteiArray;//从堆中删除或释放数组占用的地址空间,否则将会有内
存泄漏
}〃函数结束
留意:iArray不是一个堆变量。它是一个局部指针变量,指向堆中未命名的一个数
组。
一般认为在C中分为这几个存储区
chars[]"abc";〃栈
char〃栈
char*p3="123456";〃:L23456\0在常量区,p3在栈上。
staticintc=0;〃全局(静态)初始化区
pl=(char*)malloc(10);
p2=(char*)malloc(20);
〃安排得来得10和20字节的区域就在堆区。
strcpy(pl,"123456");
〃123456\0放在常量区,编译器可能会将它与p3所指向的"123456”优化成
一块。
)
还有就是函数调用时会在栈上有一系列的保留现场及传递参数的操作。
栈的空间大小有限定,VC的缺省是2M。栈不够用的状况一般是程序中安排了大量数
组和递归函数层次太深。有一点必需知道,当一个函数调用完返回后它会释放该函数中全
部的栈空间。栈是由编译器自动管理的,不用你操劳。
堆是动态安排内存的,并且你可以安排使用很大的内存。但杲用不好会产牛内存泄漏。
并且频繁地malloc和free会产生内存碎片(有点类似磁盘碎片),由于C安排动态
内存时是直找匹配的内存的。而用栈则不会产生碎片。
在栈上存取数据比通过指针在堆上存取数据快些。
一般大家说的堆栈和栈是一样的,就是栈(slack),而说堆时才是堆he叩
栈是先入后出的,一般是由高地址向低地址生长。
转载的此外一篇:
堆(heap)和栈(stack)是C/C++编程不行避开会遇到的两个基本概念。首先,这两个概
念都可以在讲数据结构的书中我到,他们都是基本的数据结构,虽然栈更为简洁一些。
在具体的C/C++编程框架中,这两个概念并不是并行的。对底层机器代码的争论可以
揭示,栈是机器系统供应的数据结构,而堆则是C/C++函数库供应的。
具体地说,现代计算机(串行执行机制),都直接在代码底层支持栈的数据结构。这体
现在,有特地的寄存器指向栈所在的地址,有特地的机器指令完成数据入栈出栈的操作。
这种机制的特点是效率高,支持的数据有限,一般是整数,指针,浮点数等系统直接
支持的数据类型,并不直接支持其他的数据结构。由于栈的这种特点,对栈的使用在程序
中是特别频繁的。对子程序的调用就是直接采用栈完成的。机器的call指令里隐含了把返
回地址推入栈,然后四蟀专至子程序地址的操作,而子程序中的ret指令则隐含从堆栈中弹
出返回地址并勘桀之的操作。C/C++中的自动变量是直接采用栈的例子,这也就是为什么
当函数返回时,该函数的自动变量自动失效的缘由。
和栈不同,堆的数据结构并不是由系统(无论是机器系统还是操作系统)支持的,而
是由函数库供应的。基本的malloc/realloc/free函数维护了一套内部的堆数据结构。当程
序使用这些函数去获得新的内存空间时,这套函数首先试图从内部堆中直找可用的内存空
间,假如没有可以使用的内存空间,则试图采用系统调用来动态增加程序数据段的内存大
小,新安排得到的空间首先被组织进内部堆中去,然后再以适当的形式返回给调用者。当
程序释放安排的内存空间时,这片内存空间被返回内部堆结构中,可能会被适当的处理(比
如和其他空闲空间合并成更大的空闲空间),以更适合下一次内存安排申请。这套简单的安
排机制实际上相当于一个内存安排的缓冲池(Cache),使用这套机制有如下若干缘由:
1、系统调用可能不支持任意大小的内存安排。有些系统的系统调用只支持固定大小及
其倍数的内存恳求(按页安排);这样的话对于大量的小内存分类来说会造成铺张。
2、系统调用申请内存可能是代价昂贵的。系统调用可能涉及用户态和核心态的转换。
3、没有管理的内存安排在大量简单内存的安排释放操作下很简洁造成内存碎片。
堆和栈的对比:
从以上学问可知,栈是系统供应的功能,特点是快速高效,缺点是有限制,数据不敏
捷;而堆是函数库供应的功能,特点是敏捷便利,数据适应面广泛,但是效率有肯定降低。
栈是系统数据结构,对于进程/线程是唯一的;堆是函数库内部数据结构,不肯定唯一。不
同堆安排的内存无法相互操作。栈空间分静态安排和动态安排两种。静态安排是编译器完
成的,比如自动变量(auto)的安排。动态安排由alloca函数完成。栈的动态安排无需释
放(是自动的),也就没有释放函数。为可移植的程序起见,栈的动态安排操作是不被鼓舞
的!堆空间的安排总是动态的,虽然程序结束时全部的数据空间都会被释放回系统,但是
精确的申请内存/释放内存匹配是良好程序的基本要素。
五大内存分区
在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和
常量存储区。
栈:就是那些由编译器在需要的时候安排,在不需要的时侯自动清除的变量的存储区。
里面的变量通常是局部变量、函数参数等。
堆:就是那些由new安排的内存块,他们的释放编译器不去管,由我们的应用程序去
掌握,一般一个new就要对应一个delete.假如程序员没有释放掉,那么在程序结束后,
操作系统会自动回收。
自由存储区:就是那些由malloc等安排的内存块,他和堆是特别相像的,不过它是用
free来结束自己的生命的。
全局/静态存储区:全局变量和静态变量被安排到同一块内存中,在以前的C语言中,
全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一
块内存区。
常量存储区:这是一块比较特别的存储区,他们里面存放的是常量,不允许修改(当
然,你要通过非正值手段也可以修改,而日方法很多)
明确区分堆与栈
在bbs上,堆与栈的区分问题,似乎是一个永恒的话题,由此可见,初学者对此往往
是混淆不清的,所以我打算拿它第一个开刀。
首先,我们举一个例子:
voidf(){int*p=newint[5];}
这条短短的一句话就包含了堆与栈,看到new,我们首先就应当想到,我们安排了一
块堆内存,那么指针P呢?他安排的是一块栈内存,所以这句话的意思就是:在栈内存中
存放了一个指向一块堆内存的指针P。在程序会先确定在堆中安排内存的大小,然后调用
operatornew安排内存,然后返回这块内存的首地址,放入栈中,他在VC6下的汇编代
码如下:
00401028push14h
0040102Acalloperatornew(00401060)
0040102Faddesp,4
00401032movdwordptr[ebp-8],eax
00401035moveax,dwordptr[ebp-8]
00401038movdwordptr[ebp-4],eax
这里,我们为了简洁并没有释放内存,那么该怎么去释放呢?是deletep么?哦,错
了,应当是delete[]p,这是为了告知编译器:我删除的是一个数组,VC6就会依据相应
的Cookie信息去进行释放内存的工作。
好了,我们回到我们的主题:堆和栈毕竟有什么区分?
主要的区分由以下几点:
1、管理方式不同;
2、空间大小不同;
3、能否产生碎片不同;
4、生长方向不同;
5、安排方式不同;
6、安排效率不同;
管理方式:对于栈来讲,是由编译器自动管理,无需我们手工掌握;对于堆来说,释
放工作由程序员掌握,简洁产生memoryleak。
空间大小:一般来讲在32位系统下,堆内存可以达到4G的空间,从这个角度来看堆
内存几乎是没有什么限制的。但是对于栈来讲,一般都是有肯定的空间大小的,例如,在
VC6下面,默认的栈空间大小是1M(似乎是,记不清晰了I当然,我们可以修改:
打开工程依次操作菜单如下Project-〉Setting-〉Link在Category中选中Output,
然后在Reserve中设定堆栈的最大值和commit
留意:reserve最小值为4Byte;commit是保留在虚拟内存的页文件里面,它设置的
较大会使栈开拓较大的值,可能增加内存的开销和后动时间。
碎片问题:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造
成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,由于栈是先进后出
的队列,他们是如此地一对应,以至于永久都不行能有一个内存块从栈中间弹出,在他
弹出之前,在他上面的后进的栈内容已经被弹出,具体的可以参考数据结构,这里我们就
不再一争论了。
生长方向:对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;对于
栈来讲,它的生长方向是向下的,是向着内存地址减小的方向增长。
安排方式:堆都是动态安排的,没有静态安排的堆。栈有2种安排方式:静态安排和
动态安排。静态安排是编译器完成的,比如局部变量的安排。动态安排由alloca函数进行
安排,但是栈的动态安排和堆是不同的,他的动态安排是由编译器进行释放,无需我们手
工实现。
安排效率:栈是机器系统供应的数据结构,计算机会在底层对栈供应支持:安排特地
的寄存器存放栈的地址,压栈出栈都有特地的指令执行,这就打算了栈的效率比较高。堆
则是C/C++函数库供应的,它的机制是很简单的,例如为了安排一块内存,库函数会依据
肯定的算法(具体的算法可以参考数据结构/操作系统)在堆内存中搜寻可用的足够大小的
空间,假如没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增
加程序数据段的内存空间,这洋就有机会分到足够大小的内存,然后进行返回。明显,堆
的效率比栈要低得多。
从这里我们可以看到,堆和栈相比,由于大量new/delete的使用,简洁造成大量的
内存碎片;由于没有特地的系统支持,效率很低;由于可能引发用户态和核心态的切换,
内存的申请,代价变得更加昂贵。所以栈在程序中是应用最广泛的,就算是函数的调用也
采用栈去完成,函数调用过程中的参数,返回地址,EBP和局部变量都采纳栈的方式存放。
所以,我们推举大家尽量用栈,而不是用堆。
虽然栈有如此众多的好处,但是由于和堆相比不是那么敏捷,有时候安排大量的内存
空间,还是用堆好一些。
无论是堆还是栈,都要防止越界现象的发生(除非你是有意使其越界),由于越界的结
果要么是程序崩溃,要么是摧毁程序的堆、栈结构,产生以想不到的结果,就算是在你的程
序运行过程中,没有发生上面的问题,你还是要当心,说不定什么时候就崩掉,那时候
debug可是相当困难的:)
对了,还有T牛事,假如有人把堆栈合起来说,那它的意思是栈,可不是堆,呵呵,
清晰了?
static用来掌握变量的存储方式和可见性
函数内部定义的变量,在程序执行到它的定义处时,编译器为它在栈I■安排空间,函
数在栈上安排的空间在此函数执行结束时会释放掉,这样就产生了一个问题:假如想将函
数中此变量的值保存至下一次调用时,如何实现?
最简洁想到的方法是定义一个全局的变量,但定义为一个全局变量有很多缺点,最明
显的缺点是破坏了此变量的访问范围(使得在此函数中定义的变量,不仅仅受此函数掌握\
需要一个数据对象为整个类而非某个对象服务,同时又力求不破坏类的封装性,即要
求此成员隐蔽在类的内部,对外不行见。
static的内部机制:
静态数据成员要在程序一开头运行时就必需存在。由于函数在程序运行中被调用,所
以静态数据成员不能在任何函数内安排空间和初始化。
这样,它的空间安排有三个可能的地方,一是作为类的外部接口的头文件,那里有类
声明;二是类定义的内部实现,那里有类的成员函数定义;三是应用程序的main()函数
前的全局数据声明和定义处。
静态数据成员要实际地安排空间,故不能在类的声明中定义(只能声明数据成员1类
声明只声明一个类的"尺寸和规格",并不进行实际的内存安排,所以在类声明中写成定义
是错误的。它也不能在头文件中类声明的外部定义,由于那会造成在多个使用该类的源文
件中,对其重复定义。
static被引入以告知编译器,将变量存储在程序的静态存储区而非栈上空间,静态数
据成员按定义消失的先后挨次依次初始化,留意静态成员嵌套时,要保讦所嵌套的成员已
经初始化了。消退时的挨次是初始化的反挨次。
static的优势:
可以节约内存,由于它是全部对象所公有的,因此,对多个对象来说,静态数据成员
只存储一处,供全部对象共用。静态数据成员的值对每个对象都是一样,但它的值是可以
更新的。只要对静态数据成员的值更新一次,保证全部对象存取更新后的相同的值,这样
可以提高时间效率。
引用静态数据成员时,采纳如下格式:
〈类名〉::〈静态成员名〉
假如静态数据成员的访问权限允许的话(即public的成员),可在程序中,按上述格
式来引用静态数据成员。
PS:
(1)类的静态成员函数是属于整个类而非类的对象,所以它没有this指
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 随州市随县2025-2026学年第二学期六年级语文第五单元测试卷部编版含答案
- 本溪市桓仁满族自治县2025-2026学年第二学期六年级语文第五单元测试卷部编版含答案
- 晋中市介休市2025-2026学年第二学期六年级语文第五单元测试卷部编版含答案
- 潍坊市安丘市2025-2026学年第二学期五年级语文第六单元测试卷(部编版含答案)
- 眉山地区仁寿县2025-2026学年第二学期六年级语文第五单元测试卷部编版含答案
- 锡林郭勒盟正蓝旗2025-2026学年第二学期六年级语文第五单元测试卷部编版含答案
- 包头市东河区2025-2026学年第二学期六年级语文第五单元测试卷部编版含答案
- 电器策划方案
- 深度解析(2026)《CBT 4386-2015集装箱绑扎杆存放架》
- 深度解析(2026)《CBT 3557-1995船用防火风闸》
- 2025年工业CT在军事弹药失效分析报告
- 2026年浙江单招酒店管理专业面试经典题含答案含应急处理题
- SJG 171-2024建筑工程消耗量标准
- 浙江省金丽衢十二校2026届高三上学期一模试题 英语 含解析
- 新疆维吾尔自治区小学五年级下学期数学第二单元测试卷-因数和倍数单元检测
- 专升本康复治疗2025年物理治疗学测试试卷(含答案)
- 2025年教职人员个人总结
- 钉钉OA管理系统
- 17918-2025港口散粮装卸系统粉尘防爆安全规范
- 2025高二英语阅读理解专项训练120篇
- 2026年版全国助理社会工作师《社会工作实务》考试题含答案(培优a卷)
评论
0/150
提交评论