要說堆、棧的區(qū)別,首先要有一個概念:一個進程的4G虛擬地址空間劃分:(如圖) 整體上從低地址到高地址可以劃分為:3G的用戶空間和1G的內(nèi)核空間。 用戶空間中:從低地址到高地址分別為:128M的不可以訪問區(qū);.text指令段;.data數(shù)據(jù)段;.bss數(shù)據(jù)段;... ;heap堆區(qū)(自低地址向高地址開辟空間);....;stack棧區(qū)(自高地址向低地址開辟空間);...... ---------------------------------------------(簡要說明各個段的作用 詳細介紹下面兩份) 堆區(qū)(heap)。用于動態(tài)內(nèi)存分配。堆在內(nèi)存中位于BSS區(qū)和棧區(qū)之間。一般由程序員分配和釋放,若程序員不釋放,程序結束時有可能由OS回收。 棧區(qū)。由編譯器自動分配釋放,存放函數(shù)的參數(shù)值、局部變量的值等。其操作方式類似于數(shù)據(jù)結構中的棧。每當一個函數(shù)被調(diào)用,該函數(shù)返回地址和一些關于調(diào)用的信息,比如某些寄存器的內(nèi)容,被存儲到棧區(qū)。然后這個被調(diào)用的函數(shù)再為它的自動變量和臨時變量在棧區(qū)上分配空間,這就是C實現(xiàn)函數(shù)遞歸調(diào)用的方法。每執(zhí)行一次遞歸函數(shù)調(diào)用,一個新的??蚣芫蜁皇褂茫@樣這個新實例棧里的變量就不會和該函數(shù)的另一個實例棧里面的變量混淆。 下面一個例子: void f() { int* p=new int[5]; } 這條短短的一句話就包含了堆與棧,關鍵new指示分配了一塊堆內(nèi)存,而指針P分配的是一塊棧內(nèi)存,所以這句話的意思就是:在棧內(nèi)存中存放了一個指向一塊堆內(nèi)存的指針p。在程序會先確定在堆中分配內(nèi)存的大小,然后調(diào)用operator new分配內(nèi)存,然后返回這塊內(nèi)存的首地址,放入棧中。 二者區(qū)別: 1、申請方式不同:堆的話,程序員動態(tài)申請,new和malloc()申請的空間;棧,由編譯器在需要的時候分配,在不需要的時候自動清除的變量的存儲區(qū)。里面的變量通常是局部變量、函數(shù)參數(shù)等。 2、管理方式不同。堆,程序員自己管理,若沒有free、delete釋放,程序結束后由OS釋放。棧,系統(tǒng)管理。 3、空間大小不同。棧是自高址向低地址擴展的結構,是一塊連續(xù)內(nèi)存區(qū)域,棧頂?shù)牡刂泛蜅5淖畲笕萘渴窍到y(tǒng)預先規(guī)定好的,當申請的空間超過棧的剩余空間時,將提示溢出。因此,用戶能從棧獲得的空間較小,通常為1M,也有2M的,可修改。 Linux下,可用命令:ulimit -s 查看棧大小 并重新設置大小。 堆是自低地址向高地址擴展的數(shù)據(jù)結構(它的生長方向與內(nèi)存的生長方向相同),是不連續(xù)的內(nèi)存區(qū)域。因為系統(tǒng)是用鏈表來存儲空閑內(nèi)存地址的,且鏈表的遍歷方向是由低地址向高地址。由此可見,堆獲得的空間較靈活,也較大。堆的大小受限于計算機系統(tǒng)中有效的虛擬內(nèi)存。一般來講在32位系統(tǒng)下,堆內(nèi)存可以達到2.9G的大小。(除去1G的內(nèi)核空間,幾乎占滿3G的用戶空間) 4、申請后系統(tǒng)的響應: 棧:只要棧的空間大于所申請空間,系統(tǒng)將為程序提供內(nèi)存,否則將報異常提示棧溢出。 堆:操作系統(tǒng)有一個記錄空閑內(nèi)存地址的鏈表,當系統(tǒng)收到程序的申請時,會遍歷該鏈表,尋找第一個空間大于所申請空間的堆結點,然后將該結點從空閑鏈表中刪除,并將該結點的空間分配給程序,另外,對于大多數(shù)系統(tǒng),會在這塊內(nèi)存空間中的首地址處記錄本次分配的大小,這樣,代碼中的free語句才能正確的釋放本內(nèi)存空間。另外,找到的堆結點的大小不一定正好等于申請的大小,系統(tǒng)會自動的將多余的那部分重新放入空閑鏈表中。 對于堆來講,頻繁的malloc/free勢必會造成內(nèi)存空間的不連續(xù),從而造成大量的碎片,使程序效率降低。對于棧就不會存在這個問題。 堆上頻繁的new delete會產(chǎn)生內(nèi)存碎片,棧上是連續(xù)的空間則不會有這個問題。 6)分配效率:棧是機器系統(tǒng)提供的數(shù)據(jù)結構,計算機會在底層對棧提供支持:分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執(zhí)行,這就決定了棧的效率比較高。堆則是C/C++函 數(shù)庫提供的,它的機制是很復雜的,例如為了分配一塊內(nèi)存,庫函數(shù)會按照一定的算法,在堆內(nèi)存中搜索可用的足夠大小的空間,如果沒有足夠大小的空間(可能是 由于內(nèi)存碎片太多),就有可能調(diào)用系統(tǒng)功能去增加程序數(shù)據(jù)段的內(nèi)存空間,這樣就有機會分到足夠大小的內(nèi)存,然后進行返回。顯然,堆的效率比棧要低得多。 推薦一篇文章,詳細介紹4G虛擬地址空間中各個段。 |
|