C语言中,内存分为五个区域,分别是堆、栈、空闲存储区、全局/静态存储区和常量存储区。栈是变量的存储区,需要时由编译器分配,不需要时自动清除。里面的变量一般是局部变量,函数参数等,堆就是new分配的那些内存块。他们的发布编译器不关心他们,由我们的应用程序控制。一般来说,一个new对应一个delete。如果程序员不释放,操作系统会在程序结束后自动回收。free存储区就是malloc等分配的那些内存块,它和heap很像,只不过是用free来结束它的生命。全局/静态存储区,全局变量和静态变量分配到同一块内存中。在以前的C语言中,全局变量分为初始化的和未初始化的。C中没有这种区别,它们共享同一个空间。一块内存。常量存储区,这是一个比较特殊的存储区,里面存放的是常量,不允许修改(当然也可以通过非法手段修改,方法有很多种,在《const的思考》一文中,我给出了6个methods)在bbs上明确区分堆和栈,堆和栈的区别似乎是一个永恒的话题。看得出来,初学者往往对此一头雾水,所以我决定先拿他来说。一个手术。首先我们举个例子:voidf(){int*p=newint[5];}这短短的一句话,包含了堆和栈。我们看到new首先应该想到我们分配了一块堆内存,那指针p呢?他分配了一块栈内存,所以这句话的意思就是:栈内存中存放了一个指向一块堆内存的指针p。程序会先判断分配的内存在堆中的大小,然后调用operatornew分配内存,然后返回这块内存的首地址入栈。其在VC6下的汇编代码如下:00401028push14h0040102Acalloperatornew(00401060)0040102Faddesp,400401032movdwordptr[ebp-8],eax00401035moveax,dwordptr[ebp-8]00401038movdwordptr[ebp-we4],eax这里为了简单没有释放内存如何释放它?是删除p吗?哦,不对,应该是delete[]p,这是告诉编译器:我删除的是一个数组,VC6会根据对应的Cookie信息释放内存。好了,回到我们的话题:堆和栈有什么区别?主要区别如下:管理方式不同;不同的空间大小;不同的碎片;不同的成长方向;不同的分配方法;分配效率不同;管理方式:对于栈,由编译器自动管理,无需我们手动控制;对于堆,释放工作由程序员控制,容易出现内存泄漏。空间大小:一般来说,在32位系统下,堆内存可以达到4G。从这个角度看,堆内存几乎没有限制。但是对于栈来说,一般都有一定的空间大小。比如VC6下默认的栈空间大小是1M(好像是,记不清了)。当然我们可以修改:打开工程,操作菜单如下:Project->Setting->Link,在Category中选择Output,然后在Reserve中设置栈的最大值和commit。注意:reserve的最小值为4Byte;commit保留在虚拟内存的pagefile中,如果设置的大一些,栈会开辟一个较大的值,可能会增加内存开销和启动时间。碎片问题:对于堆来说,频繁的new/delete必然会造成内存空间的不连续,从而产生大量的碎片,降低程序效率。对于栈来说,这个问题是不存在的,因为栈是一个先进后出的队列,他们是一一对应的,永远不可能有一个内存块从中间弹出堆。它上面的向后堆栈的内容已经弹出。具体可以参考数据结构,这里不一一讨论。增长方向:对于堆来说,增长方向是向上的,即朝着内存地址递增的方向;对于栈来说,它的增长方向是向下的,朝着内存地址递减的方向。分配方式:堆是动态分配的,没有静态分配的堆。栈的分配有两种方式:静态分配和动态分配。静态分配由编译器完成,就像局部变量的分配一样。动态分配是通过alloca函数分配的,但是栈的动态分配不同于堆。他的动态分配是编译器释放的,不需要我们手动实现。分配效率:栈是机器系统提供的一种数据结构,计算机会在底层对栈提供支持:分配一个专门的寄存器来存放栈的地址,压栈出栈,有都是专门执行的指令,这就决定了栈的效率是比较高的。堆由C/C函数库提供,其机制非常复杂。例如,为了分配一块内存,库函数会按照一定的算法(具体算法参考数据结构/操作系统)查找可用的堆内存。如果空间不够(可能是内存碎片太多),可以调用系统函数增加程序数据段的内存空间,这样才有机会分配足够的内存,然后执行return.很明显,堆比栈效率低很多。从这里我们可以看出,与栈相比,由于使用了大量的new/delete,很容易造成大量的内存碎片;由于没有专门的系统支持,效率很低;因为这可能会导致用户态和核心态的切换,内存的申请变得更加昂贵。因此,栈在程序中的应用最为广泛。甚至函数调用也是使用栈完成的。函数调用过程中的参数、返回地址、EBP和局部变量都存放在栈中。因此我们建议大家尽量使用栈而不是堆。小结虽然栈有这么多的好处,但是由于和堆相比没有那么灵活,所以有时候使用堆来分配大量的内存空间反而更好。不管是堆还是栈,都要防止越界现象的发生(除非你故意让它越界),因为越界的结果要么是程序崩溃,要么程序的堆和栈结构被破坏,导致意想不到的结果。在你的程序运行过程中,如果没有出现以上问题,你还是要小心,它随时可能崩溃,那时候调试是相当困难的:)
