c#靜態方法和實例方法的內存分配問題

方法 (Method) 是一種類型定義,所以,它被存放在 Type Object 上,Type Object 是一個被分配在託管堆上的特殊類型,在同一個 AppDomain 中,每一個類型,都對應一個全局的 Type Object。每個引用類型的實例,都包含一個指向它的直接類型的 Type Object 的指針,每個 Type Object 也存在類似的指針,用來標識它的直接父類型的 Type Object。

當調用靜態方法時,CLR 會根據方法調用去尋找其對應的 Type Object,然後,把方法 JIT,JIT 之後的方法是本機代碼,可以直接運行,然後,這部分代碼被加載進入內存,方法的參數被加載進入當前執行棧,原來的執行上下文地址也被記錄到執行棧;方法開始執行,執行完後,執行棧中的返回地址被讀出,然後 CLR 利用本機跳轉指令,跳轉到該返回至繼續執行。

當調用實例方法時,CLR 會根據實例的 Type Object 指針找到對應的 Type Object,然後,把方法 JIT,JIT 之後的方法是本機代碼,可以直接運行,然後,這部分代碼被加載進入內存,該實例對象,以及方法的參數被加載進入當前執行棧 (實例對象永遠是第一個參數,即 arg0,利用 ldarg0 指令進行讀取),原來的執行上下文地址也被記錄到執行棧;方法開始執行,執行完後,執行棧中的返回地址被讀出,然後 CLR 利用本機跳轉指令,跳轉到該返回至繼續執行。

如果方法已經被 JIT 過,則不會被第二次 JIT。

方法在 IL 中是以字節流的形式存在的,所以,它仍然會佔據內存。

方法 JIT 之後會被駐留在該進程的地址空間裏面,因此,它也會在運行時佔據內存。

方法的元數據存放在程序集 MethodRef 以及 MethodDef 表中。

定義在值類型上的實例方法就比較麻煩了,大家有興趣可以想想它怎麼執行的。因爲值類型沒有 Type Object 指針。

如果值類型實現一個接口,在執行接口的方法實現的時候就更加麻煩了,大家也可以想想,歡迎討論!

最後,

大家都以爲“ 靜態方法在堆上分配內 存,實例方法在堆棧上

這句話完全不靠譜,不要被迷惑了。。。只要提到方法,它就一定在 Type Object 上,也就是被分配在託管堆上。

發佈了44 篇原創文章 · 獲贊 73 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章