1. 程式人生 > >Win - 程式是怎樣跑起來的——程式載入時會生成棧和堆

Win - 程式是怎樣跑起來的——程式載入時會生成棧和堆

EXE檔案的內容分為再配置資訊、變數組和函式組,這一點想必大家都清楚了吧。不過,當程式載入到記憶體後,除此之外還會額外生成兩個組,那就是棧和堆。棧是用來儲存函式內部臨時使用的變數(區域性變數【注1】),以及函式呼叫時所用的引數的記憶體區域。堆是用來儲存程式執行時的任意資料及物件的記憶體領域(圖)。

【注1】區域性變數是指只在呼叫函式時存在於記憶體中的變數。例如,在程式碼清單8-1中,WinMain函式的處理中的ave和buff都是區域性變數。全域性變數是指程式執行時一直存在於記憶體中的變數。程式碼清單8-1中的title就是全域性變數。

圖:載入到記憶體的程式由4部分構成

① 不管是什麼程式,程式的內容都是由處理和資料構成的。大多數程式語言都是用函式來表示處理、用變數來表示資料。

EXE檔案中並不存在棧及堆的組。棧和堆需要的記憶體空間是在EXE檔案載入到記憶體後開始執行時得到分配的。因而,記憶體中的程式,就是由用於變數的記憶體空間、用於函式的記憶體空間、用於棧的記憶體空間、用於堆的記憶體空間這4部分構成的。當然,在記憶體中,載入Windows等作業系統的記憶體空間又是另外一回事了(圖)。

棧及堆的相似之處在於,他們的記憶體空間都是在程式執行時得到申請分配的【注2】。不過,在記憶體的使用方法上,二者存在些許不同。棧中對資料進行儲存和捨棄(清理處理)的程式碼,是由編譯器自動生成的,因此不需要程式設計師的參與。使用棧的資料的記憶體空間,每當函式被呼叫時都會得到申請分配,並在函式處理完畢後自動釋放。與此相對,堆的記憶體空間,則要根據程式設計師編寫的程式,來明確進行申請分配或釋放。

【注2】棧和堆的大小,可以由程式設計師任意指定。在高階程式語言中,編譯器會自動生成指定棧和堆大小的程式碼,並將其附加到程式中。

根據程式語言的不同,對堆用的記憶體空間進行申請分配和釋放的程式的編寫方法也是多種多樣的。C語言中是通過malloc()函式來進行申請分配、通過free()函式來釋放的。而C++中則是通過new運算子來申請分配、通過delete運算子來釋放的。無論是C語言還是C++,如果沒有在程式中明確釋放堆的記憶體空間,那麼即使在處理完畢後,該記憶體空間仍會一直殘留。這個現象稱為記憶體洩露(memory leak),它是令C語言及C++的程式設計師們十分頭疼的一個bug(程式的錯誤)。如果記憶體洩露一直存在的話,就有可能會造成記憶體不足而導致宕機。這就好比,如果水龍頭一直嘀嗒嘀嗒地漏水,那麼一晚上的時間水桶就可能會裝滿並溢位。