蔡學鏞 - .NET中间语言
.NET CLR 和 Java VM 都是堆栈式虚拟机(Stack-Based VM)。Java VM有约200个指令,每个指令都是1byte的opcode,后面接不等的参数;.NET CLR 有超过220条指令,但有些是使用相同的opcode,大部分是1byte,但也有2byte的。
圖 1
下面是一個簡單的 C# 原始碼:
using System; public class Test { public static void Main(String[] args) { int i=1; int j=2; int k=3; int answer = i+j+k; Console.WriteLine("i+j+k="+answer); } }
將此原始碼編譯之後,可以得到一個 EXE 檔案。我們可以透過 ILDASM.EXE 來反組譯 EXE 以觀察 IL。我將 Main() 的 IL 反組譯條列如下,這裡共有十八道 IL 指令,有的指令(例如 ldstr 與 box)後面需要接參數,有的指令(例如 ldc.i4.1 與 add)後面不需要接參數。
ldc.i4.1 stloc.0 ldc.i4.2 stloc.1 ldc.i4.3 stloc.2 ldloc.0 ldloc.1 add ldloc.2 add stloc.3 ldstr "i+j+k=" ldloc.3 box [mscorlib]System.Int32 call string [mscorlib]System.String::Concat(object, object) call void [mscorlib]System.Console::WriteLine(string) ret
此程式執行時,關鍵的記憶體有三種,分別是:
- Managed Heap:這是動態配置(Dynamic Allocation)的記憶體,由 Garbage Collector(GC)在執行時自動管理,整個 Process 共用一個 Managed Heap。
- Call Stack:這是由 .NET CLR 在執行時自動管理的記憶體,每個 Thread 都有自己專屬的 Call Stack。每呼叫一次 method,就會使得 Call Stack 上多了一個 Record Frame;呼叫完畢之後,此 Record Frame 會被丟棄。一般來說,Record Frame 內紀錄著 method 參數(Parameter)、返回位址(Return Address)、以及區域變數(Local Variable)。Java VM 和 .NET CLR 都是使用 0, 1, 2… 編號的方式來識別區域變數。
- Evaluation Stack:這是由 .NET CLR 在執行時自動管理的記憶體,每個 Thread 都有自己專屬的 Evaluation Stack。前面所謂的堆疊式虛擬機器,指的就是這個堆疊。
指令ldc是将参数存储至堆栈Evaluation Stack;zhi
指令stloc是将变量存储至堆栈Call Stack;後面有一連串的示意圖,用來解說在執行時此三種記憶體的變化。首先,在進入 Main() 之後,尚未執行任何指令之前,記憶體的狀況如圖 1 所示:
圖 1
接著要