行程與行程抽象

堆疊(stack)

想像門邊一疊自助餐托盤:進入一個步驟時你在最上面加一個托盤,離開時就拿走最上面的那個,永遠是後進先出。執行中程式的每一次函式呼叫就像加一個托盤。堆疊就是行程記憶體中記錄「當前活躍的函式呼叫鏈」的區域,每次呼叫的區域變數、參數與返回位址都疊在上面。

當函式被呼叫時,程式把一個堆疊框推進堆疊:一塊存放該次呼叫的參數、區域變數,以及返回位址(告訴 CPU 函式結束後要從哪裡接續)的區塊。當函式返回時,它的框被彈出,那些區域變數自動被釋放,執行從儲存的返回位址繼續。由於呼叫以嚴格的後進先出順序巢狀並返回,堆疊乾淨地長大與縮小,不會碎裂。在經典配置中,堆疊位於位址空間的高端並往下生長,朝著往上生長的堆積而去,兩者共用中間的空隙。

堆疊快速而自動,這正是區域變數便宜的原因,但它也有限且僵硬。框必須以與建立相反的順序釋放,所以堆疊無法保存「必須活得比其函式更久」的資料(那是堆積的工作)。兩種經典的失敗:堆疊溢位,當過深的遞迴或巨大的區域陣列把堆疊推過界限(往往侵入堆積或一個守衛頁)而使程式當機;以及懸空指標,當程式碼回傳一個其堆疊框早已被彈出的區域變數的位址。

main 呼叫 f,f 又呼叫 g。堆疊中有三個框(main,上面是 f,再上面是 g)。當 g 返回時,它的框被彈出、它的區域變數消失;接著 f 返回,它的框也被彈出。

後進先出:最近的呼叫在最上面,也最先返回。

絕不要回傳指向區域變數的指標。函式返回時它的堆疊框被彈出,指標便懸空,使用它是未定義行為。

又稱
call stackexecution stack堆疊呼叫堆疊