Visual Studio 偵錯器在托管堆檢視、堆疊深度分析、JIT 代碼檢視等場景下力有不逮。Windbg + SOS (Son of Strike) 是 CLR 團隊官方提供的底層診斷利器,能直達執行引擎核心。
char 強制轉換的 JIT 代碼class Program {
static void Main(string[] args) {
Program b = new Program();
b.test();
Console.ReadLine();
}
public void test() {
int i = 67;
Console.WriteLine((char)i); // 變數轉換
Console.WriteLine((char)67); // 常數轉換
i = 1;
}
}
.attach <PID> 或 File → Attach to Process.load C:\Windows\Microsoft.NET\Framework\v2.0.50727\SOS.dll~ → 切換至主執行緒 ~0s!name2ee TestConcoleApp.exe TestConcoleApp.Program.test
MethodDesc: 00ab2ff0
JITTED Code Address: 00d000f8
!dumpil 00ab2ff0
IL_0001: ldc.i4.s 67
IL_0003: stloc.0
IL_0004: ldloc.0
IL_0005: conv.u2 ; 關鍵指令:int → unsigned int16 → 擴展為 int32 入棧
IL_0006: call Console.WriteLine
IL_000c: ldc.i4.s 67
IL_000e: call Console.WriteLine ; 常數直接呼叫,無 conv.u2
!u 00d000f8
Normal JIT generated code
TestConcoleApp.Program.test()
push esi
push eax
mov dword ptr [esp], ecx
cmp dword ptr ds:[0AB2DD8h], 0
je 00d0010b
call mscorwks!CorLaunchApplication+0x108b4 (7a08e179)
xor esi, esi
nop
mov esi, 43h ; 'C' = 67
movzx ecx, si ; ★★★ 關鍵:movzx 實現 conv.u2(零擴展 16 位 → 32 位)
call mscorlib_ni!Console.WriteLine (793b8b9c)
nop
mov ecx, 43h
call mscorlib_ni!Console.WriteLine (793b8b9c)
nop
mov esi, 1
pop ecx
pop esi
ret
conv.u2 的真實面目char 為無符號 16 位,int 為有符號 32 位。隱式轉換可能丟失符號位/高位,conv.u2 明確語義:「截取低 16 位,零擴展至 32 位」。(char)67 編譯期已知,直接推導為 mov ecx, 43h,無 conv.u2 痕跡。movzx ecx, si 完美對應 conv.u2,零擴展 16 位暫存器 si 至 32 位 ecx。Dim i As Integer = 67
Console.WriteLine(Chr(i)) ' Chr 為函數呼叫,無 conv.u2
Console.WriteLine(Chr(67))
VB IL 同樣無 conv.u2,證實此為 C# 編譯器語言層面的類型安全行為。
| 命令 | 用途 |
|---|---|
| 查找 MethodDesc 與 JIT 地址 | |
| 輸出 IL 代碼 | |
| 反組譯 JIT 原生碼 | |
| 檢視物件內容 | |
| !dumpobj 縮寫 | |
| 尋找物件 GC 根引用 | |
| 顯示 GC Heap 狀態 | |
| 列舉堆中特定類型物件 | |
| 顯示托管堆疊 | |
| 列舉所有 CLR 執行緒 |
Windbg + SOS 是通往 CLR 內核的鑰匙。本文以簡單的類型轉換為切入點,展示從 IL 到 JIT 代碼的完整分析鏈路。掌握這套工具鏈,能讓你在記憶體洩漏、死鎖、效能抖動、異常崩潰等疑難雜症面前,擁有「核磁共振」級的診斷能力。