堆和棧是兩種內存分配的統稱。
一.棧
- 棧會存放函數的局部變量,函數的返回地址等。棧有"LIFO"(後進先出)的特點。
- 棧由操作系統分配,自動回收.
- 棧的大小受到限制。在x86體系下,棧一般通過esp 指向棧幀頂部,ebp指向底部
- 不斷的嵌套或者爲局部變量分配空間,可能導致棧溢出。這時候會觸發一個異常
- 在執行完一個函數的時候,其中的變量都會從堆棧中彈出。
- 無需親自管理內存,變量會自動分配和釋放。
- 棧一般是高地址向低地址擴展,函數返回的時候,會通過返回原來的位置來釋放空間。
- 棧對應的是CPU的一級緩存,一級緩存在CPU內部,訪問快,比較小
二.堆
- 堆是計算機中不會自動管理的區域,不受CPU嚴格管理,它是內存中更加自由浮動的區域。
- 我們可以通過封裝好的函數(malloc/calloc/new…)來進行內存分配
- 內核維護了一個
brk
指針,指向堆的頂部,將堆視爲大小不同的塊的集合來進行維護,每一個塊就是一個連續的虛擬內存,要麼是已經分配的,要麼是空閒的,已經分配的塊顯式的保留爲供應用程序使用,空閒塊可以分配內存。 - 堆是從低地址向高地址擴展,是不連續的內存區域。系統通過鏈表來存儲空閒內存地址。
- 一般在堆的頭部用一個字節存放堆的大小。
- 堆一般是CPU二級緩存,CPU和內存之間的地址,訪問比一級緩存慢,但是比讀內存快,容量比較大
- 在多線程的情況下,線程有自己的棧,彼此共享創建他們的進程的堆。
- 堆分配的內存必須進行手動釋放
三.區別
管理方式:
- 對於棧來講,是由編譯器自動管理。
- 對於堆來說,分配釋放工作由程序員控制,容易造成內存泄露。
空間大小:
- 一般來講在32位系統下,堆內存可以達到4G的空間,從這個角度來看堆內存幾乎是沒有什麼限制的。但是對於棧來講,一般都是有一定的空間大小的。
碎片問題:
- 對於堆來講,頻繁的new/delete勢必會造成內存空間的不連續,從而造成大量的碎片,使程序效率降低。對於棧來講,則不會存在這個問題,操作系統會自動回收.
生長方向:
- 對於堆來講,向着內存地址增加的方向增長(低地址向高地址);
- 對於棧來講,向着內存地址減小的方向增長(高地址向低地址)。
分配方式:
- 堆都是動態分配(運行期)的,沒有靜態分配(編譯期)的堆。
- 棧有2種分配方式:靜態分配和動態分配(alloca()函數可以動態分配棧的內存空間,釋放的時候由編譯器自己釋放)。
分配效率:
- 計算機在底層對棧提供支持,分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執行,這就決定了棧的效率比較高。
- 堆則是C/C++函數庫提供的,效率比棧要低得多。