堆和栈的区别

堆内存分配灵活,比如,当我们对一些数据大小不知道时,可以采用堆内存的方式进行动态分配,但是要记得自己去释放,栈在程序中应用也很广泛,比如函数的调用,局部变量等都是采用栈的方式,它的分配和释放不需要人工干扰,由编译器自动完成。在程序中,我们少不了和这两个概念打交道,下面就来分析它们之间具体有哪些不同。

  • 管理方式不同

堆:需要由程序员自主分配和释放,所以容易产生内存泄露问题。

栈:分配和释放由编译器自主完成,无需程序员去控制。

  • 空间大小不同

堆:大小几乎没有什么限制,比如在32位系统中,堆内存可以达到CPU最大寻找空间4GB。

栈:有一定空间大小,有编译器指定,当然自己也可以修改编译器的默认设置。

  • 碎片问题

堆:它是由new/delete来分配的,如果频繁的使用它们来分配和释放,则会造成内存空间不连续,即产生大量的磁盘碎片,会降低程序运行效率。

栈:因为它本身是一种先进后出的数据结构,数据之间是紧密排列的,中间不会留有空隙。所以没有碎片的问题。

  • 生成方向

堆:生长方向是向上的,即向着内存地址增加的方向增长。

栈:生成方向向下,即向着内存地址减小的方向增长。

  • 分配方式

堆:堆只能是动态分配,没有静态分配的堆。

栈:栈有两种方式分配,静态分配和动态分配。静态分配是由编译器完成的,比如函数中的局部变量分配。动态分配由alloca函数完成,但是它的动态分配是与堆是不同的,它是由编译器去释放的,无需程序员手工干预。

  • 分配效率

堆:它的分配由C/C++函数库提供,分配机制复杂。比如分配一块内存,库函数会按照一定的算法在堆内存在搜索找到可用的足够大小的空间,如果没有足够大小的空间(可能因为内存碎片太多),则可能会调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后返回。在重新分配的过程中,也可能还会引发用户态和内核态之间的切换,显然分配的效率要低。

栈:计算机会在底层对栈提供支持:它会分配专门寄存器存放栈的地址,而且压栈出栈都有专门的指令来执行,所以分配效率要高。