本文通過windbg調試一個簡單的程式,來清除說明.Net framework中class type,value type的記憶體配置方式的不同,以及object內部的重要組成MethodTable的作用
用於說明問題的source code如下:
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Collections;
6
7 namespace VSDebug
8 {
9 class StringHolder
10 {
11 public string StringData;
12 public StringHolder(string stringData)
13 {
14 StringData = stringData;
15 }
16 }
17
18 class TestClass
19 {
20 public ArrayList Holders;
21 [STAThread]
22 static void Main(string[] args)
23 {
24 TestClass testClass = new TestClass();
25 TestClass testClass1 = new TestClass();
26 testClass.Holders = new ArrayList();
27 for (int i = 0; i < 10; ++i)
28 {
29 testClass.Holders.Add(new StringHolder("Hello"));
30 }
31 Console.ReadLine();
32 }
33
34 }
35 }
36
設定project 的debug屬性為enabled unmanaged code debugging,在31行設定breakpoint,然後press F5開始調試,並開啟intermediate window開始windbg sos 調試
.load sos
extension C:\Windows\Microsoft.NET\Framework\v2.0.50727\sos.dll loaded
!dumpheap -stat
PDB symbol for mscorwks.dll not loaded
total 2086 objects
Statistics:
MT Count TotalSize Class Name
79100f58 1 12 System.Security.Permissions.SecurityPermission
790fdc5c 1 20 System.Text.StringBuilder
79104368 1 24 System.Collections.ArrayList
790fcc48 1 24 System.Reflection.Assembly
0023304c 2 24 VSDebug.TestClass
790feba4 1 28 System.SharedStatics
790fd0f0 3 36 System.Object
790ff734 2 40 System.RuntimeType
79100e38 1 44 System.Security.FrameSecurityDescriptor
790ff120 1 44 System.AppDomainSetup
7912dd40 1 64 System.Char[]
79100a18 2 72 System.Security.PermissionSet
790fe17c 1 72 System.ExecutionEngineException
790fe0e0 1 72 System.StackOverflowException
790fe044 1 72 System.OutOfMemoryException
790fed00 1 100 System.AppDomain
003c7508 7 100 Free
002330cc 10 120 VSDebug.StringHolder
790fe284 2 144 System.Threading.ThreadAbortException
7912d8f8 9 8992 System.Object[]
790fd8c4 2037 129576 System.String
Total 2086 objects
下面對each column作簡要說明:
MT-〉MethodTable. 首先說明MethodTable的作用。我們知道每種type可以有多個instance。在C++中,每個instance,其每個field可以享有獨立的space,而對於type的method提供一個公用的method入口地址。也就是說不管多少個相同類型的instance,其都指向了同一個同一的函數入口地址。在這個函數入口地址描述表中記錄了各個函數的入口地址。而MethodTable就有點類似的作用。自不過所有Assembly都是自描述的,因此我們可以從MethodTable中,可以知道相應的instance。因此通過相應的debug命令!dumpheap -mt MTAddress可以知道在MethodTable中相關聯的所有instance了
Count ->某個特定MethodTable地址下相關聯的objects的數目
TotalSize->所佔空間
Class Name->object descriptive information
請看下面:
!dumpheap -mt 0023304c
Address MT Size
0286168c 0023304c 12
02861698 0023304c 12
total 2 objects
Statistics:
MT Count TotalSize Class Name
0023304c 2 24 VSDebug.TestClass
Total 2 objects
可以看出,在該MethodTable中關聯的有2個objects,一個object address是:0286168c,而另外一個object address 是:02861698
在.net中,我們知道,對於class type的object,其object ref是佔用stack上的空間,而 object ref則指向了GC heap上的空間。剛才我們已經知道在heap上有2個VsDebug.TestClass的object,並且其Heap Address也已給出。
下面看看在stack是否有相應的VsDebug.TestClass ref指向其object.
!dso
OS Thread Id: 0xed8 (3800)
ESP/REG Object Name
ecx 02861788 System.Object[]
0014eef0 028616a4 System.Collections.ArrayList
0014eef8 028617d8 VSDebug.StringHolder
0014f064 028616a4 System.Collections.ArrayList
0014f068 028617d8 VSDebug.StringHolder
0014f06c 0286168c VSDebug.TestClass
0014f074 02861788 System.Object[] (System.Object[])
0014f29c 02861698 VSDebug.TestClass
0014f2a4 02861660 System.Object[] (System.String[])
0014f2bc 02861660 System.Object[] (System.String[])
0014f394 02861660 System.Object[] (System.String[])
0014f53c 02861660 System.Object[] (System.String[])
0014f564 02861660 System.Object[] (System.String[])
果然,可以看到在stack上看到2個指向heap上的VsDebug.TestClass 類型的object :)