寫堆棧,一是由於在工做中有時會碰到,腦子裏有這個概念可是又沒有一個完整的框架;二是我剛開始工做時,導師問我malloc,我竟徹底不知這個函數,更不知道malloc是從堆中分配內存,因此如今補上。算法
文中不少語句都是引用他人,無心抄襲,在此說明一下,如有冒犯,請告知。框架
這篇文章先從程序內存佈局講起,說明堆棧在Linux進程內存空間中的位置,而後再分別說明堆棧的基本概念、做用。函數
Linux進程內存佈局佈局
現代的應用程序都是運行在內存空間中的,在32位的系統裏,這個內存空間擁有4GB的尋址能力。實際上,每一個應用程序(或者說進程)都有本身獨立的內存空間,即經過虛擬內存來實現(具體虛擬內存知識暫不介紹)。性能
大多數操做系統都會將4GB的內存空間中的一部分分配給內核使用,應用程序沒法訪問這一段內存,這一部份內存空間稱之爲內核空間。Linux默認將高地址的1GB內存空間分配給內核。剩下的3GB內存空間稱之爲用戶空間。在用戶空間裏,也有許多默認的內存區域,例如堆棧,可執行文件映像,保留區。下圖是一個Linux典型的內存佈局:操作系統
棧設計
1、什麼是棧blog
棧是現代計算機程序裏最重要的概念之一,幾乎每個程序都使用了棧,沒有棧就沒有函數,沒有局部變量。進程
在經典的計算機科學中,棧被定義爲特殊的容器,用戶能夠將數據壓入棧中(入棧,push),也能夠將已經壓入棧中的數據彈出(出棧,pop),且棧遵照一條規則,即先入後出。內存
經典的操做系統中,棧老是向下生長。在i386下,棧頂由稱爲esp的寄存器進行定位,壓棧的操做會使棧頂的地址減少,彈出的操做使棧頂的地址增大。
2、棧的做用是什麼
棧在程序運行中具備舉足輕重的地位,最重要的,棧保存了一個函數調用所須要的維護信息,一般被稱爲堆棧幀(stack frame)或活動記錄。堆棧幀通常包括如下幾方面的內容:
--函數的返回地址和參數
--臨時變量:包括函數的非靜態局部變量以及編譯器自動生成的其餘臨時變量
--保存的上下文:包括在函數調用先後須要保持不變的寄存器
堆
1、堆的定義和做用
光有棧對於面向過程的程序設計還遠遠不夠,由於棧上的數據在函數返回的時候就會被釋放掉,因此沒法將數據傳遞至函數外部。而全局變量沒法動態產生,只能在編譯的時候定義,不少狀況下缺少表現力。在這種狀況下,堆(heap)是惟一的選擇。
堆是一塊巨大的內存空間,經常佔據整個虛擬空間的絕大部分。在這片空間裏,程序能夠請求一塊連續內存,並自由的使用,這塊內存在程序主動放棄以前會一直保持有效。
malloc是libc裏面實現的一個函數,中文叫動態內存分配,用於從堆中獲取內存。可是malloc是如何實現的呢?有一種實現方法是,將進程的內存管理交給操做系統去處理,既然內核管理着進程的地址空間,那麼若是它提供一個系統調用,可讓程序使用這個系統調用來申請內存,這是一種理論上可行的方法,可是實際這樣去作性能會很是差,由於每次程序申請或者釋放堆空間都須要進行系統調用,而系統調用的性能開銷很是大,當程序對堆的操做越頻繁時,這樣作的後果是會嚴重影響程序的性能。比較好的作法是程序向操做系統申請一塊適當大小的空間,而後由程序本身管理,而具體來說,管理着堆空間分配的每每是程序的運行庫。
運行庫至關因而向操做系統「批發」了一塊較大的堆空間,而後「零售」給程序用。當所有「售完」或者有大量的內存需求時,再根據實際需求向操做系統「進貨」。運行庫在向程序零售堆空間時,必須管理他批發來的堆空間,不能把同一塊地址出售兩次,因而運行庫須要一個算法來管理堆空間,即堆的分配算法。