1. 程式人生 > >WinDbg探究CLR底層(1)

WinDbg探究CLR底層(1)

一、什麼是應用程式域

作業系統由於其穩定性與可靠性的要求,都會使用隔離層,來確保執行在某個隔離層內的程式碼不會對其他隔扇層的程式碼產生影響。如Windows通過程序來實現這種隔離機制,所能的可執行程式碼、資料、以及其它資源都被包含在程序中,系統其他程序通常不允許對它們進行訪問。同理、.NET應用程式同樣也是被侷限在程序內執行,但是.NET還進一步引入了另一種邏輯隔離層,也就是我們這裡說的應用程式域(AppDomain)

二、如何檢視應用程式域

下面用一個例子看看應用程式域:

using System;

namespace Sample01
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World");

            Console.ReadLine();
        }
    }
}

這段程式碼是一個簡單的控制檯程式,沒有任何邏輯。執行起來,使用WinDbg附加到程序,然後執行以下命令:

0:006> .load sos
0:006> !EEVersion
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll - 
PDB symbol for clr.dll not loaded
4.7.3190.0 retail
Workstation mode
SOS Version: 4.6.1648.0 retail build
0:006> !DumpDomain
The version of SOS does not match the version of CLR you are debugging.  Please
load the matching version of SOS for the version of CLR you are debugging.
CLR Version: 4.7.3190.0
SOS Version: 4.6.1648.0
--------------------------------------
System Domain:      7230d5a8
LowFrequencyHeap:   7230d8cc
HighFrequencyHeap:  7230d918
StubHeap:           7230d964
Stage:              OPEN
Name:               None
--------------------------------------
Shared Domain:      7230d258
LowFrequencyHeap:   7230d8cc
HighFrequencyHeap:  7230d918
StubHeap:           7230d964
Stage:              OPEN
Name:               None
Assembly:           00cb30e8 [C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll]
ClassLoader:        00cb2bd0
  Module Name
6a681000    C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll

--------------------------------------
Domain 1:           00c7f090
LowFrequencyHeap:   00c7f4fc
HighFrequencyHeap:  00c7f548
StubHeap:           00c7f594
Stage:              OPEN
SecurityDescriptor: 00c87cb0
Name:               Sample01.exe
Assembly:           00cb30e8 [C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll]
ClassLoader:        00cb2bd0
SecurityDescriptor: 00cb3060
  Module Name
6a681000    C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll

Assembly:           00cb6718 [E:\Workspace\DotNet\WinDbgInspectCLR\Sample01\bin\Debug\Sample01.exe]
ClassLoader:        00cb6c18
SecurityDescriptor: 00cb6b90
  Module Name
00be401c    E:\Workspace\DotNet\WinDbgInspectCLR\Sample01\bin\Debug\Sample01.exe

通過!DumpDomain命令輸出,可以看到,這個示例執行程式所在程序中3個應用程式域,SystemSharedDomain 1。其中,Domain 1是預設的應用程式域,它的名字就是映像本身的名字(Sample01.exe)。

在每個應用程式域的輸出訊息中包含以下內容:

  1. System Domain: 指向應用程式域的指標。這個指標可以作為DumpDomain命令的輸入引數,以得到指定應用程式域的資訊,如:

    0:006> !DumpDomain 7230d5a8
    The version of SOS does not match the version of CLR you are debugging.  Please
    load the matching version of SOS for the version of CLR you are debugging.
    CLR Version: 4.7.3190.0
    SOS Version: 4.6.1648.0
    --------------------------------------
    System Domain:      7230d5a8
    LowFrequencyHeap:   7230d8cc
    HighFrequencyHeap:  7230d918
    StubHeap:           7230d964
    Stage:              OPEN
    Name:               None
  2. LowFrequencyHeapHighFrequencyHeapStubHeap:.Net程式是建立在中間語言(IL)的基礎上的,因此,每個應用程式域都有相就的MSIL程式碼。在JIT編譯成MSIL過程中,JIT編譯器需要儲存與編譯過程相關的資料,如機器程式碼與方法表(Method Table)等。因此,每個應用程式域都需要建立一定資料的堆(Heap)來儲存這些資料。LowFrequencyHeap中則儲存的是一些更新、訪問較少的資料,HighFrequencyHeap包含的是被訪問頻繁的資料,而StubHeap中包含的是CLR執行互用性呼叫 (例如COM互用性或者平臺呼叫)時需要的輔助資料。

  3. Name:應用程式域名稱。

  4. Assembly:在應用程式域中載入的所有程式集。從輸出中來看,應用程式域Sample01.exe中載入了兩個程式集:mscorlib.dll、Sample01.exe。其中更包含程式集版本、底層程式集資料結構地址,如Sample01.exe程式集的地址為00c7f090

三、各應用程式域的作用

系統應用程式域

  1. 建立其他兩個應用程式域(共享應用程式域和預設應用程式域)。
  2. 將mscorlib.dll載入到共享應用程式域中(在下面將進一步討論)。
  3. 記錄程序中所有其他的應用程式域,包括提供載入/解除安裝應用程式域等功能。
  4. 記錄字串池中的字串常量,因此允許任意字串在每個程序中都存在一個副本。
  5. 初始化特定型別的異常,例如記憶體耗盡異常,棧溢位異常以及執行引擎異常等。

共享應用程式域

在共享應用程式域中包含的是與應用程式域無關的程式碼。mscorlib.dll將被載入到這個應用程式域中(由系統應用程式域負責載入),此外還包括在System名稱空間中的一些基本型別(例如String、enum、ValueType、Array等)。在大多數情況下,非使用者程式碼(non-user code)將被載入到共享應用程式域中,不過也有一些機制可以將使用者程式碼(user code)載入到共享應用程式域中。啟用了CLR的應用程式域可以通過載入器的優化屬性來注入使用者程式碼。

 預設應用程式域

通常,.NET程式在預設應用程式域中執行。位於預設應用程式域中的所有程式碼都只有在這個域中才是有效的。由於應用程式域實現了一種有邏輯並且可靠的邊界,因此任何跨越應用程式域的訪問操作都必須通過.NET遠端物件來進行。

四、動態建立、解除安裝應用程式域

前面我們看到程式啟動時,系統幫我們建立的預設應用程式域,然後手動建立應用程式域也是可以的,程式碼如下:

using System;

namespace Sample02
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Before CreateDomain");
            Console.ReadLine();

            AppDomain domain = AppDomain.CreateDomain("NewDomain");
            

            Console.WriteLine("After CreateDomain, Before Unload");
            Console.ReadLine();

            AppDomain.Unload(domain);

            Console.WriteLine("After Unload");
            Console.ReadLine();
        }
    }
}

程式開始執行時:

有三個應用程式域:System Domain、Shared Domain、Domain 1

0:006> !DumpDomain
--------------------------------------
System Domain:      7230d5a8
LowFrequencyHeap:   7230d8cc
HighFrequencyHeap:  7230d918
StubHeap:           7230d964
Stage:              OPEN
Name:               None
--------------------------------------
Shared Domain:      7230d258
LowFrequencyHeap:   7230d8cc
HighFrequencyHeap:  7230d918
StubHeap:           7230d964
Stage:              OPEN
Name:               None
Assembly:           00df8468 [C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll]
ClassLoader:        00df8520
  Module Name
6a681000    C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll

--------------------------------------
Domain 1:           00dd7da0
LowFrequencyHeap:   00dd820c
HighFrequencyHeap:  00dd8258
StubHeap:           00dd82a4
Stage:              OPEN
SecurityDescriptor: 00dd0120
Name:               Sample02.exe
Assembly:           00df8468 [C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll]
ClassLoader:        00df8520
SecurityDescriptor: 00dfc018
  Module Name
6a681000    C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll

Assembly:           00dff8d8 [E:\Workspace\DotNet\WinDbgInspectCLR\Sample02\bin\Debug\Sample02.exe]
ClassLoader:        00dff318
SecurityDescriptor: 00dfcd60
  Module Name
00ec401c    E:\Workspace\DotNet\WinDbgInspectCLR\Sample02\bin\Debug\Sample02.exe

Enter繼續執行,多一個應用程式域Domain 2

0:006> !DumpDomain
The version of SOS does not match the version of CLR you are debugging.  Please
load the matching version of SOS for the version of CLR you are debugging.
CLR Version: 4.7.3190.0
SOS Version: 4.6.1648.0
--------------------------------------
System Domain:      7230d5a8
LowFrequencyHeap:   7230d8cc
HighFrequencyHeap:  7230d918
StubHeap:           7230d964
Stage:              OPEN
Name:               None
--------------------------------------
Shared Domain:      7230d258
LowFrequencyHeap:   7230d8cc
HighFrequencyHeap:  7230d918
StubHeap:           7230d964
Stage:              OPEN
Name:               None
Assembly:           00df8468 [C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll]
ClassLoader:        00df8520
  Module Name
6a681000    C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll

--------------------------------------
Domain 1:           00dd7da0
LowFrequencyHeap:   00dd820c
HighFrequencyHeap:  00dd8258
StubHeap:           00dd82a4
Stage:              OPEN
SecurityDescriptor: 00dd0120
Name:               Sample02.exe
Assembly:           00df8468 [C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll]
ClassLoader:        00df8520
SecurityDescriptor: 00dfc018
  Module Name
6a681000    C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll

Assembly:           00dff8d8 [E:\Workspace\DotNet\WinDbgInspectCLR\Sample02\bin\Debug\Sample02.exe]
ClassLoader:        00dff318
SecurityDescriptor: 00dfcd60
  Module Name
00ec401c    E:\Workspace\DotNet\WinDbgInspectCLR\Sample02\bin\Debug\Sample02.exe

--------------------------------------
Domain 2:           00e0cf00
LowFrequencyHeap:   00e0d36c
HighFrequencyHeap:  00e0d3b8
StubHeap:           00e0d404
Stage:              OPEN
SecurityDescriptor: 00e09fe0
Name:               NewDomain
Assembly:           00df8468 [C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll]
ClassLoader:        00df8520
SecurityDescriptor: 00dfccd8
  Module Name
6a681000    C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll

Assembly:           00e17398 [E:\Workspace\DotNet\WinDbgInspectCLR\Sample01\bin\Debug\Sample01.exe]
ClassLoader:        00e21d90
SecurityDescriptor: 00dfc128
  Module Name
011949f4    E:\Workspace\DotNet\WinDbgInspectCLR\Sample01\bin\Debug\Sample01.exe

再次按Enter繼續執行,應用程式域Domain 2中的Sample01.exe被解除安裝, 目前還沒查到為什麼Domain 2 沒被整體解除安裝,我猜想是因為mscorlib.dll還在還在使用。

0:006> !DumpDomain
The version of SOS does not match the version of CLR you are debugging.  Please
load the matching version of SOS for the version of CLR you are debugging.
CLR Version: 4.7.3190.0
SOS Version: 4.6.1648.0
--------------------------------------
System Domain:      7230d5a8
LowFrequencyHeap:   7230d8cc
HighFrequencyHeap:  7230d918
StubHeap:           7230d964
Stage:              OPEN
Name:               None
--------------------------------------
Shared Domain:      7230d258
LowFrequencyHeap:   7230d8cc
HighFrequencyHeap:  7230d918
StubHeap:           7230d964
Stage:              OPEN
Name:               None
Assembly:           00aa7a90 [C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll]
ClassLoader:        00aa8818
  Module Name
6a681000    C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll

--------------------------------------
Domain 1:           00a7f410
LowFrequencyHeap:   00a7f87c
HighFrequencyHeap:  00a7f8c8
StubHeap:           00a7f914
Stage:              OPEN
SecurityDescriptor: 00a869f0
Name:               Sample02.exe
Assembly:           00aa7a90 [C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll]
ClassLoader:        00aa8818
SecurityDescriptor: 00aa7a08
  Module Name
6a681000    C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll

Assembly:           00aab3b8 [E:\Workspace\DotNet\WinDbgInspectCLR\Sample02\bin\Debug\Sample02.exe]
ClassLoader:        00aab050
SecurityDescriptor: 00aab5f0
  Module Name
0097401c    E:\Workspace\DotNet\WinDbgInspectCLR\Sample02\bin\Debug\Sample02.exe

--------------------------------------
Domain 2:           00ab93d8
LowFrequencyHeap:   00ab9844
HighFrequencyHeap:  00ab9890
StubHeap:           00ab98dc
Stage:              HANDLETABLE_NOACCESS
Name:               NewDomain
Assembly:           00aa7a90 [C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll]
ClassLoader:        00aa8818
SecurityDescriptor: 00abd780
  Module Name
6a681000    C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll

Assembly:           00acdce0 []
ClassLoader:        00acde80
SecurityDescriptor: 00abcb48
  Module Name
04cf49f4    Dynamic Module

六、總結

一直聽說應用程式域,但對其概念、作用不甚瞭解,因此結合WinDbg來試圖對其進行深入理解,加深印象,後續系列會繼續使用WinDbg對CLR底層進行研究。

參考文獻