行程與行程抽象

堆積(heap)

想像一間大型的公用儲物室,在烹調進行到一半時,你可以突然去取用任何你臨時需要的檯面空間,用完後再歸還。你不必事先宣告會用到多少。堆積就是行程記憶體中用於動態配置的區域:程式在執行時要求的記憶體,數量可能事先未知,用完後再交還。

當程式呼叫像 C 的 malloc、C++ 的 new(或高階語言建立物件)這類操作時,它是在向堆積管理器要求一塊特定大小的記憶體。管理器找到一塊空閒區塊、標記為使用中、把它的位址交回;之後程式釋放它(或由垃圾回收器回收),空間便可重複利用。堆積通常位於資料區段與 BSS 的上方,並隨著要求更多記憶體而往上朝堆疊生長。由於配置與釋放可以任意順序發生,堆積可能變得碎裂——出現太小而無法再利用的空隙——這也是為什麼堆積管理比堆疊單純的「長大、縮小」更複雜的原因之一。

當資料必須活得比建立它的函式更久、或它的大小只有在執行時才知道(例如一份隨使用者輸入而增長的清單)時,資料就住在堆積裡。代價是責任:在手動管理記憶體的語言中,忘了釋放會造成記憶體洩漏,而釋放兩次或使用已釋放的記憶體會造成毀損與當機。一個常見的誤解是把「堆積」當成資料結構中的堆積(用於優先佇列的那種);記憶體的堆積與它無關,只是借用了同一個詞。

呼叫 p = malloc(40) 向堆積要求 40 位元組;程式使用 p,然後呼叫 free(p) 把它歸還。若始終不呼叫 free,那 40 位元組就洩漏了:在程式餘下的生命中一直被保留卻無法再使用。

用 malloc 取用,用 free 歸還;忘記歸還就洩漏記憶體。

堆積配置靈活,但比堆疊配置更慢、更棘手;像洩漏、重複釋放、使用已釋放記憶體這類臭蟲都是堆積的問題,而非堆疊的。

又称
dynamic memoryfree store堆積動態記憶體