堆和棧的區別

2021-06-21 17:02:59 字數 1742 閱讀 2963

面試被問到了堆和棧的區別,當時是第一次聽到這個問題,頓時感覺這個問題有點抽象。因為程式記憶體部分有堆和棧的概念,資料結構裡面也有堆和棧的概念,不知道面試官說的是哪個。當我提出來疑問之後,面試官說隨你答。我就把兩個方面都簡單說了下。回來後到網上搜了下,這才知道面試官想問的應該是程式記憶體裡面堆和棧的區別。想想也是,資料結構裡面堆和棧的區別很明顯,根本不需要去區分嘛。參考他人的部落格,這裡對程式記憶體裡面堆和棧的區別做個概括,以方便大家使用。

文獻1解釋了c++在記憶體管理中,將記憶體分為5個部分。

常量區:主要儲存的是常量字串以及在編譯的時候就知道其值的那些變數。因為每個類型別的物件都需要呼叫建構函式,所以常量區裡面不可能存在類型別的常量。常量區內的所有資料在程式的執行期間都一直存在著。

全域性/靜態區:全域性變數或者靜態變數都存放在此。

棧:區域性變數都存放在棧裡面。在棧中,對變數儲存空間的分配要比堆快。這主要是因為棧記憶體的分配僅僅涉及到指標的增加,不需要額外複雜的操作。此外,物件是在棧記憶體分配後立即被構造,在棧記憶體釋放後立即被銷毀。所以,碼農是沒有機會來對棧中已分配但未初始化的記憶體進行操作。堆:堆屬於動態記憶體區,由malloc分配,free釋放(很多blog說堆是由new/delete來分配和釋放,自由儲存區是由malloc/free來分配和釋放,關於這一點很有爭議性,主要是因為堆和自由儲存區的區別就存在很大爭議,所以碼農不必太糾結於這個,重點關注與棧和堆(動態記憶體)的區別就是了)。在堆中,物件的生命週期可能會小於所分配的堆記憶體的生命週期。這是因為堆內存在被分配之後可以稍後再進行初始化,在物件被銷毀之後可以稍後再進行記憶體釋放。所以,在物件不存在而記憶體卻存在時,我們可以通過使用void*來操作這塊堆記憶體。自由儲存區:跟堆類似,自由儲存區是動態記憶體區的一種。是由new/delete來分配和釋放。自由儲存區中,物件的生命週期和在堆中是類似的。所以除了概念上的不同,沒有必要對這兩種動態儲存區做進一步的區分。

上述給出了c++記憶體區5個部分的描述。可以看出棧記憶體是由系統自動分配和釋放的,碼農對棧記憶體控制的自由度比較低。而堆記憶體是由碼農手動申請分配和釋放,雖然控制的自由度提公升了,但是也帶來了潛在的危險。如果碼農只申請了記憶體,忘記了釋放,那麼就會造成程式的記憶體洩露。

文獻2:對棧和堆的區分做了乙個很好的總結。

首先,我們先來了解下棧記憶體申請和堆記憶體申請時,系統都做了哪些工作。

棧記憶體申請:如定義個區域性變數int i,或者乙個區域性的陣列int array[10024]時,只要棧剩餘記憶體空間還能滿足需求,棧頂指標就增加到一定位置以申請相應的棧記憶體。如果棧剩餘記憶體無法滿足需求時,就是碼農所見到的棧溢位錯誤了。

堆記憶體申請:作業系統有乙個記錄空閒記憶體結點的鍊錶。當碼農申請棧記憶體時,系統都會遍歷鍊錶結點以找出乙個合適的堆結點返回給碼農(至於哪個合適,就涉及到c++的記憶體分配演算法了)。如果沒有找到合適的,那麼就返回null

比較一下棧記憶體申請和堆記憶體申請,系統所做的工作,我們可以明確以下幾點:

棧記憶體的申請效率要高於堆記憶體的申請效率。

棧記憶體的申請空間大小限制比較大。因為棧頂的位址和棧的最大容量是系統預先設定好的,一旦申請的棧記憶體大小超出棧中剩餘容量,就會出現棧溢位。而申請的堆記憶體大小只要不超過系統的虛擬記憶體就不會遭遇返回null。

文獻1:

文獻2:

堆和棧區別

一 預備知識 程式的記憶體分配 乙個由c c 編譯的程式占用的記憶體分為以下幾個部分 1 棧區 stack 由編譯器自動分配釋放 存放函式的引數值,區域性變數的值等。其 操作方式類似於資料結構中的棧。2 堆區 heap 一般由程式設計師分配釋放,若程式設計師不釋放,程式結束時可能由os回 收 注意它...

堆和棧區別

管理方式 棧由編譯器自動管理 堆由程式設計師控制,使用方便,但易產生記憶體洩露。生長方向 棧向低位址擴充套件 即 向下生長 是連續的記憶體區域 堆向高位址擴充套件 即 向上生長 是不連續的記憶體區域。這是由於系統用鍊錶來儲存空閒記憶體位址,自然不連續,而鍊錶從低位址向高位址遍歷。空間大小 棧頂位址和...

堆和棧區別

一 預備知識 程式的記憶體分配 乙個由c c 編譯的程式占用的記憶體分為以下幾個部分 1 棧區 stack 由編譯器自動分配釋放 存放函式的引數值,區域性變數的值等。其 操作方式類似於資料結構中的棧。2 堆區 heap 一般由程式設計師分配釋放,若程式設計師不釋放,程式結束時可能由os回 收 注意它...