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個應用程序域,System、Shared、Domain 1。其中,Domain 1是默認的應用程序域,它的名字就是映像本身的名字(Sample01.exe)。
在每個應用程序域的輸出消息中包含以下內容:
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
LowFrequencyHeap、HighFrequencyHeap、StubHeap:.Net程序是建立在中間語言(IL)的基礎上的,因此,每個應用程序域都有相就的MSIL代碼。在JIT編譯成MSIL過程中,JIT編譯器需要保存與編譯過程相關的數據,如機器代碼與方法表(Method Table)等。因此,每個應用程序域都需要創建一定數據的堆(Heap)來存儲這些數據。LowFrequencyHeap中則保存的是一些更新、訪問較少的數據,HighFrequencyHeap包含的是被訪問頻繁的數據,而StubHeap中包含的是CLR執行互用性調用 (例如COM互用性或者平臺調用)時需要的輔助數據。
Name:應用程序域名稱。
Assembly:在應用程序域中加載的所有程序集。從輸出中來看,應用程序域Sample01.exe中加載了兩個程序集:mscorlib.dll、Sample01.exe。其中更包含程序集版本、底層程序集數據結構地址,如Sample01.exe程序集的地址為
00c7f090
。
三、各應用程序域的作用
系統應用程序域
- 創建其他兩個應用程序域(共享應用程序域和默認應用程序域)。
- 將mscorlib.dll加載到共享應用程序域中(在下面將進一步討論)。
- 記錄進程中所有其他的應用程序域,包括提供加載/卸載應用程序域等功能。
- 記錄字符串池中的字符串常量,因此允許任意字符串在每個進程中都存在一個副本。
- 初始化特定類型的異常,例如內存耗盡異常,棧溢出異常以及執行引擎異常等。
共享應用程序域
在共享應用程序域中包含的是與應用程序域無關的代碼。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底層進行研究。
參考文獻
- 《.NET高級調試》
- WinDbg 命令三部曲
WinDbg探究CLR底層(1) - 應用程序域