堆棧與託管堆

來源:互聯網
上載者:User

這是雨痕的的文章,原文在這裡。

關於 CLR 記憶體管理員模式,各種書籍和網路文章各執一詞,十分混亂。大多數時候也只是泛泛提到 "託管堆" 和 "堆棧" 而已,其實際過程非常複雜。鑒於沒有一個統一的說法,我也不能保證本文的準確性。

當 CLR 建立執行線程時,會依據 mainfest 中的 ".stackreserve 0x00100000" 指令為當前線程分配 1MB 的呼叫堆疊(Call Stack)記憶體。呼叫堆疊不同於託管堆(Managed Heap),它不負責儲存託管引用對象,只是用來維護方法調用次序,執行 IL 指令。而當我們使用 call、callvirt 等指令調用一個方法時,CLR 會在呼叫堆疊中分配一個稱之為堆疊框架(Stack Frame) 的記憶體塊用於執行目標方法代碼。就是一個堆疊框架的記憶體。

,每個堆疊框架中包含三塊記憶體:參數表 (Argument Table) 用於儲存方法參數,內部變數表 (Local Variable Table) 儲存方法局部變數(.locals init),而 計算堆棧 (Evaluation Stack) 則是 IL 代碼執列區域。執行 IL 指令前,相關指令資料(Data)或其地址(Address)被壓入計算堆棧,然後執行指令並彈出計算結果,執行下一個指令時繼續重複這樣的動作,直到方法調用結束。這三部分記憶體共同構成了一個方法的記憶體執行環境,需要注意的是其大小單位並不是 byte,而是 slot。每個 slot 可以儲存一個託管單元(對象),我們可以在方法體中使用 .maxstack 指令控制當前方法計算堆棧的大小。

.method private hidebysig static void Test1(int32& x) cil managed
{
  .maxstack 8
}

回到方法調用流程,當我們使用 call 等指令調用一個方法時,CLR 為目標方法在呼叫堆疊上新分配一個堆疊框架,並將方法參數從當前方法的計算堆棧彈出壓入目標方法的參數表中,接著執行流程跳轉到目標方法。當執行 .locals init 指令時,會在其內部變數表中建立相應的內部變數,然後使用目標方法的計算堆棧完成 IL 指令執行。當目標方法 IL 指令結束時,其傳回值(如果有)會被彈出(pop)並壓入(push)最初調用者的計算堆棧中,ret 指令將控制權返回給調用者,目標方法堆疊框架被拋棄,所佔用記憶體被釋放。

相關概念

棧(Stack)和堆(Heap)不同,它是一種線性結構,而堆是一種鏈式結構。棧按照先進後出 (LIFO - Last In First Out) 的原理工作,通過一個指標來維護記憶體佔用。當我們釋放一段記憶體時,只要將指標回複到某個起始位置即可,因此它的執行效率非常高。而託管堆(Managed Heap)是動態分配的記憶體地區,由 GC 進行管理,每個進程中的所有線程共用一個託管堆。

.NET CLR 和 Java VM 都是一種被稱之為堆棧式虛擬機器(Stack-Base VM)的技術,它的執行機制和我們所熟悉的 80x86 執行方式有所不同,它並沒有寄存器的概念,他們的指令集(Instruction Set) 都是採用堆棧進行運算,首先將資料(Data)壓入棧,然後進行操作。此處的堆棧就是我們上面所說的計算堆棧(Evaluation Stack)。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.