天天看點

堆和棧的差別

1棧 - 有編譯器自動配置設定釋放 

2堆 - 一般由程式員配置設定釋放,若程式員不釋放,程式結束時可能由OS回收 

3全局區(靜态區),全局變量和靜态變量的存儲是放在一塊的,初始化的全局變量和靜 

态變量在一塊區域,未初始化的全局變量和未初始化的靜态變量在相鄰的另一塊區域。 

- 程式結束釋放 

4另外還有一個專門放常量的地方。 - 程式結束釋放 

在函數體中定義的變量通常是在棧上,用malloc, calloc, realloc等配置設定記憶體的函數分 

配得到的就是在堆上。在所有函數體外定義的是全局量,加了static修飾符後不管在哪 

裡都存放在全局區(靜态區),在所有函數體外定義的static變量表示在該檔案中有效, 

不能extern到别的檔案用,在函數體内定義的static表示隻在該函數體内有效。另外, 

函數中的 "adgfdf "這樣的字元串存放在常量區。 

比如: 

int a = 0; 全局初始化區 

char *p1; 全局未初始化區 

main() 

int b; 棧 

char s[] = "abc ";棧 

char *p2; 棧 

char *p3 = "123456 "; 123456\0在常量區,p3在棧上。 

static int c =0; 全局(靜态)初始化區 

p1 = (char *)malloc(10); 

p2 = (char *)malloc(20); 

配置設定得來得10和20位元組的區域就在堆區。 

strcpy(p1, "123456 "); 123456\0放在常量區,編譯器可能會将它與p3所指向的 "12345 

6 "優化成一塊。 

還有就是函數調用時會在棧上有一系列的保留現場及傳遞參數的操作。 

棧的空間大小有限定,vc的預設是2M。棧不夠用的情況一般是程式中配置設定了大量數組和 

遞歸函數層次太深。有一點必須知道,當一個函數調用完傳回後它會釋放該函數中所有 

的棧空間。棧是由編譯器自動管理的,不用你操心。 

堆是動态配置設定記憶體的,并且你可以配置設定使用很大的記憶體。但是用不好會産生記憶體洩漏。 

并且頻繁地malloc和free會産生記憶體碎片(有點類似磁盤碎片),因為c配置設定動态記憶體時 

是尋找比對的記憶體的。而用棧則不會産生碎片。 

在棧上存取資料比通過指針在堆上存取資料快些。 

一般大家說的堆棧和棧是一樣的,就是棧(stack),而說堆時才是堆heap. 

棧是先入後出的,一般是由高位址向低位址生長。 

堆(heap)和棧(stack)是C/C++程式設計不可避免會碰到的兩個基本概念。首先,這兩個概念 

都可以在講資料結構的書中找到,他們都是基本的資料結構,雖然棧更為簡單一些。 

在具體的C/C++程式設計架構中,這兩個概念并不是并行的。對底層機器代碼的研究可以揭示 

,棧是機器系統提供的資料結構,而堆則是C/C++函數庫提供的。 

具體地說,現代計算機(串行執行機制),都直接在代碼底層支援棧的資料結構。這展現 

在,有專門的寄存器指向棧所在的位址,有專門的機器指令完成資料入棧出棧的操作。 

這種機制的特點是效率高,支援的資料有限,一般是整數,指針,浮點數等系統直接支 

持的資料類型,并不直接支援其他的資料結構。因為棧的這種特點,對棧的使用在程式 

中是非常頻繁的。對子程式的調用就是直接利用棧完成的。機器的call指令裡隐含了把 

傳回位址推入棧,然後跳轉至子程式位址的操作,而子程式中的ret指令則隐含從堆棧中 

彈出傳回位址并跳轉之的操作。C/C++中的自動變量是直接利用棧的例子,這也就是為什 

麼當函數傳回時,該函數的自動變量自動失效的原因(因為 顔換指戳說饔們暗 狀态)。 

和棧不同,堆的資料結構并不是由系統(無論是機器系統還是作業系統)支援的,而是由 

函數庫提供的。基本的malloc/realloc/free函數維護了一套内部的堆資料結構。當程式 

使用這些函數去獲得新的記憶體空間時,這套函數首先試圖從内部堆中尋找可用的記憶體空 

間,如果沒有可以使用的記憶體空間,則試圖利用系統調用來動态增加程式資料段的記憶體 

大小,新配置設定得到的空間首先被組織進内部堆中去,然後再以适當的形式傳回給調用者 

。當程式釋放配置設定的記憶體空間時,這片記憶體空間被傳回内部堆結構中,可能會被适當的 

處理(比如和其他空閑空間合并成更大的空閑空間),以更适合下一次記憶體配置設定申請。這 

套複雜的配置設定機制實際上相當于一個記憶體配置設定的緩沖池(Cache),使用這套機制有如下若 

幹原因: 

1. 系統調用可能不支援任意大小的記憶體配置設定。有些系統的系統調用隻支援固定大小及其 

倍數的記憶體請求(按頁配置設定);這樣的話對于大量的小記憶體分類來說會造成浪費。 

2. 系統調用申請記憶體可能是代價昂貴的。系統調用可能涉及使用者态和核心态的轉換。 

3. 沒有管理的記憶體配置設定在大量複雜記憶體的配置設定釋放操作下很容易造成記憶體碎片。 

堆和棧的對比 

從以上知識可知,棧是系統提供的功能,特點是快速高效,缺點是有限制,資料不靈活 

;而棧是函數庫提供的功能,特點是靈活友善,資料适應面廣泛,但是效率有一定降低 

。棧是系統資料結構,對于程序/線程是唯一的;堆是函數庫内部資料結構,不一定唯一 

。不同堆配置設定的記憶體無法互相操作。棧空間分靜态配置設定和動态配置設定兩種。靜态配置設定是編 

譯器完成的,比如自動變量(auto)的配置設定。動态配置設定由alloca函數完成。棧的動态配置設定 

無需釋放(是自動的),也就沒有釋放函數。為可移植的程式起見,棧的動态配置設定操作是 

不被鼓勵的!堆空間的配置設定總是動态的,雖然程式結束時所有的資料空間都會被釋放回 

系統,但是精确的申請記憶體/釋放記憶體比對是良好程式的基本要素。 

可以放一塊思考 

堆和棧的生長方向恰好相反, 

|--------------| 低位址 

| 堆 | 

|--------------| 

| | | 

| I | 

| | 

| ^ | 

| 棧 | 高位址 

----------------- 

是以計算機中的堆和棧經常時放一塊講的 

nod 一般不是必要就不要動态建立,最讨厭把new出來的東西當局部變量用,用萬了馬上 

delete 的做法. 

理由 

1.棧配置設定比堆快,隻需要一條指令就呢給配所有的局部變量 

2.棧不會出現記憶體碎片 

3。棧對象好管理 

當然,某些情況下也要那麼寫,比如 

1.對象很大 

2.對象需要在某個特定的時刻構造或析夠 

3.類隻允許對象動态建立,比如VCL的大多數類 

當然,必須用堆對象時也不能躲避

繼續閱讀