一、申請方式 程序員
stack: 由系統自動分配。 例如,聲明在函數中一個局部變量int b; 系統自動在棧中爲b開闢空間。
heap: 須要程序員本身申請,並指明大小,在C中malloc函數,C++中是new運算符。
如p1 = (char *)malloc(10); p1 = new char[10];
如p2 = (char *)malloc(10); p2 = new char[20];
可是注意p一、p2自己是在棧中的。
二、申請後系統的響應
棧:只要棧的剩餘空間大於所申請空間,系統將爲程序提供內存,不然將報異常提示棧溢出。
堆:首先應該知道操做系統有一個記錄空閒內存地址的鏈表,當系統收到程序的申請時,會遍歷該鏈表,尋找第一個空間大於所申請空間的堆結點,而後將該結點從空閒結點鏈表中刪除,並將該結點的空間分配給程序。
對於大多數系統,會在這塊內存空間中的首地址處記錄本次分配的大小,這樣,代碼中的delete語句才能正確的釋放本內存空間。
因爲找到的堆結點的大小不必定正好等於申請的大小,系統會自動的將多餘的那部分從新放入空閒鏈表中。
三、申請大小的限制
棧:在Windows下,棧是向低地址擴展的數據結構,是一塊連續的內存的區域。這句話的意思是棧頂的地址和棧的最大容量是系統預先規定好的,在 Windows下,棧的大小是一個編譯時就肯定的常數,若是申請的空間超過棧的剩餘空間時,將提示Overflow。所以,能從棧得到的空間較小。
堆:堆是向高地址擴展的數據結構, 是不連續的內存區域。這是因爲系統是用鏈表來存儲的空閒內存地址的,天然是不連續的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限於計算機系統中有效的虛擬內存。因而可知,堆得到的空間比較靈活,也比較大。
四、申請效率的比較
棧由系統自動分配,速度較快。但程序員是沒法控制的。
堆是由new分配的內存,通常速度比較慢,並且容易產生內存碎片,不過用起來最方便。
另外,在 Windows下,最好的方式是用VirtualAlloc分配內存,他不是在堆,也不是棧,而是直接在進程的地址空間中保留一快內存,雖然用起來最不方便。可是速度快,也最靈活。
五、堆和棧中的存儲內容
棧:在函數調用時,第一個進棧的是主函數中函數調用後的下一條指令(函數調用語句的下一條可執行語句)的地址,而後是函數的各個參數,在大多數的C編譯器中,參數是由右往左入棧的,而後是函數中的局部變量。注意靜態變量是不入棧的。
當本次函數調用結束後,局部變量先出棧,而後是參數,最後棧頂指針指向最開始存的地址,也就是主函數中的下一條指令,程序由該點繼續運行。
堆:通常是在堆的頭部用一個字節存放堆的大小。堆中的具體內容有程序員安排。
六、存取效率的比較
char s1[] = "Hello";
char *s2 = "World";
Hello是在運行時刻賦值的,而World是在編譯時就肯定的。可是,在之後的存取中,在棧上的數組比指針所指向的字符串(例如堆)快。
七、小結
堆和棧的主 要區別由如下幾點:
一、管理方式不一樣;
二、空間大小不一樣;
三、可否產生碎片不一樣;
四、生長方向不一樣;
五、分配方式不一樣;
六、分配效率不一樣;
管理方式:對於棧來說,是由編譯器自動管理,無需咱們手工控制;對於堆來講,釋放工做由程序員控制,容易產生Memory Leak。
空間大小:通常來說在32位系統下,堆內存能夠達到4G的空間,從這個角度來看 堆內存幾乎是沒有什麼限制的。可是對於棧來說,通常都是有必定的空間大小的,例如,在VC6下面,默認的棧空間大小是1M。固然,這個值能夠修改。 算法
碎片問題:對於堆來說,頻繁的new/delete勢必會形成內存空間的不連續,從而形成大量的碎片,使程序效率下降。對於棧來說,則不會存在這個問 題,由於棧是先進後出的隊列,他們是如此的一一對應,以致於永遠都不可能有一個內存塊從棧中間彈出,在他彈出以前,在他上面的後進的棧內容已經被彈出,詳細的能夠參考數據結構。 數組
生長方向:對於堆來說,生長方向是向上的,也就是向着內存地址增長的方向;對於棧來說,它的生長方向是向下的,是向着內存地址減少的方向增加。
分配方式:堆都是動態分配的,沒有靜態分配的堆。棧有2種分配方式:靜態分配和動態分配。靜態分配是編譯器完成的,好比局部變量的分配。動態分配由alloca函數進行分配,可是棧的動態分配和堆是不一樣的,他的動態分配是由編譯器進行釋放,無需咱們手工實現。
分配效率:棧是機器系統提供的數據結構,計算機會在底層對棧提供支持:分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執行,這就決定了棧的效率 比較高。堆則是C/C++函數庫提供的,它的機制是很複雜的,例如爲了分配一塊內存,庫函數會按照必定的算法(具體的算法能夠參考數據結構/操做系統)在 堆內存中搜索可用的足夠大小的空間,若是沒有足夠大小的空間(多是因爲內存碎片太多),就有可能調用系統功能去增長程序數據段的內存空間,這樣就有機會 分 到足夠大小的內存,而後進行返回。顯然,堆的效率比棧要低得多。 數據結構
從這裏咱們能夠看到,堆和棧相比,因爲大量new/delete的使用, 容易形成大量的內存碎片;因爲沒有專門的系統支持,效率很低;因爲可能引起用戶態和核心態的切換,內存的申請,代價變得更加昂貴。因此棧在程序中是應用最普遍的,就算是函數的調用也利用棧去完成,函數調用過程當中的參數,返回地址, EBP和局部變量都採用棧的方式存放。因此,咱們推薦你們儘可能用棧,而不是用堆。 函數
雖然棧有如此衆多的好處,可是因爲和堆相比不是那麼靈活,有時候分配大量的內存空間,仍是用堆好一些。
不管是堆仍是棧,都要防止越界現象的發生(除非你是故意使其越界),由於越界的結果要麼是程序崩潰,要麼是摧毀程序的堆、棧結構,產生以想不到的結果。 spa