明晰C++内存分配的五种方法的区别

明晰C++内存分配的五种方法的区别,第1张

明晰C++内存分配的五种方法的区别,第2张

在C++中,内存分为五个区域,分别是堆、栈、空闲存储区、全局/静态存储区和常量存储区。

堆栈是变量的存储区域,需要时由编译器分配,不需要时自动清除。里面的变量通常是局部变量,函数参数等。

堆是那些由新的。它们的发布由我们的应用程序控制,与编译器无关。通常,新的对应于删除。如果程序员不释放,程序结束后操作系统会自动回收。

空闲存储区是malloc等分配的内存块。它与heap非常相似,但它以free结束其生命。

全局/静态存储区,全局变量和静态变量被分配到同一个内存中。在以前的C语言中,全局变量分为初始化的和未初始化的。C++里没有这种区分,它们共享同一个内存区域。

常量存储区,是一个特殊的存储区,里面存储的是常量,不允许修改(当然你可以用不正当的手段修改,方法有很多。在《Const的思考》一文中,我给出了六种方法)

堆和栈之间的明显区别

在bbs上,栈的区分似乎是一个永恒的话题,可见新手往往对这个比较迷茫,所以我决定把他作为第一个操作。

首先,我们来举个例子:

void f(){ int * p = new int[5];}

这个短句包含堆和栈。当我们看到new时,我们首先应该认为我们已经分配了一个堆内存。指针P呢?他分配了一个堆栈内存,所以这句话的意思是:指向一个堆栈内存的指针P存储在堆栈内存中。程序将首先确定堆中分配的内存大小,然后调用operator new来分配内存,然后返回这个内存的第一个地址并放入堆栈中。他在VC6下的汇编代码如下:

00401028 push 14h
0040102 a call operator new(00401060)
0040102 f add esp,4
00401032 mov dword ptr[ebp-8],eax
00401035 mov eax,dword ptr[ebp-8]
00401038 mov dword ptr

在这里,为了简单起见,我们没有释放内存,那么我们如何释放呢?难道是删p?澳洲,错了,应该是delete []p,这是告诉编译器:我删除了一个数组,VC6会根据对应的Cookie信息释放内存。

好了,回到我们的话题:堆和栈的区别是什么?

主要区别如下:

1.管理方式不同;

2.空的大小不同;

3.是否可以不同地产生片段;

4.成长方向不同;

5.发行方式不同;

6.分销效率不同;

管理模式:对于栈,由编译器自动管理,无需手动控制;对于堆来说,释放工作由程序员控制,容易产生内存泄漏。

大小在空之间:一般来说,32位系统下,堆内存可以达到4G 空。从这个角度来看,堆内存几乎没有限制。但就栈而言,通常在空之间有一定的大小。比如VC6下,stacks 空之间的默认大小是1M(好像,我记不太清楚了)。当然,我们可以修改:

打开项目,然后操作菜单如下:项目->设置->链接,分类选择输出,然后设置栈值,预留提交。

注意:预留的最小值是4个字节;提交是保存在虚拟内存中的页面文件。如果设置得太大,堆栈将打开一个更大的值,这可能会增加内存开销和启动时间。

碎片化:对于堆来说,频繁的new/delete必然会导致内存空的不连续,造成大量的碎片,降低程序的效率。就栈而言,这个问题是不会存在的,因为栈是先入后出的队列,而且是一一对应的,永远不可能有内存块从栈中间弹出来。在弹出之前,它上面最后一个栈的内容已经被弹出了。具体请参考数据结构,这里就不一一讨论了。

增长方向:对于堆来说,增长方向是向上的,即朝着内存地址增加的方向;就栈而言,它的增长方向是向下的,朝着内存地址减少的方向增长。

分配方法:堆是动态分配的,但是没有静态分配。栈的分配有两种方式:静态分配和动态分配。静态分配是由编译器完成的,比如局部变量的分配。动态分配是由alloca函数分配的,但是栈的动态分配和堆的动态分配是不一样的。它的动态分配是由编译器释放的,我们不需要手动实现。

分配效率:堆栈是机器系统提供的数据结构,计算机会在底层对堆栈提供支持:分配专门的寄存器来存储堆栈的地址,按下和离开堆栈时执行专门的指令,这就决定了堆栈的高效率。堆是由C/C++函数库提供的,其机制非常复杂。比如为了分配一块内存,库函数会按照一定的算法在堆内存中搜索足够大小的可用空空间(具体算法参考数据结构/操作系统)。如果没有足够大的空空间(可能是因为内存碎片太多),显然,堆的效率要比栈低得多。

从这里我们可以看出,与stack相比,heap由于使用了大量的new/delete,容易造成大量的内存碎片;因为没有专门的系统支持,效率很低;它可能会导致用户模式和核心模式之间的切换,内存的应用变得更加昂贵。因此,堆栈在程序中的应用最为广泛。甚至函数调用都是通过堆栈来完成的。函数调用过程中的参数、返回地址、EBP和局部变量都是通过堆栈存储的。因此,我们建议您尝试使用堆栈而不是堆。

虽然stack有这么多优点,但是因为和heap相比没有那么灵活,所以有时候还是用heap来分配大量内存空比较好。

无论是堆还是栈,都要防止越界的现象(除非你故意让它越界),因为越界的结果要么是程序的崩溃,要么是程序的堆和栈结构被破坏,产生意想不到的结果。即使在你的程序运行过程中没有出现上述问题,你还是要小心,说不定某个时候就会崩溃,那调试就相当困难了:)

位律师回复
DABAN RP主题是一个优秀的主题,极致后台体验,无插件,集成会员系统
白度搜_经验知识百科全书 » 明晰C++内存分配的五种方法的区别

0条评论

发表评论

提供最优质的资源集合

立即查看 了解详情