本文通过windbg调试一个简单的程序,来清除说明.Net framework中class type,value type的内存分配方式的不同,以及object内部的重要组成MethodTable的作用
用于说明问题的source code如下:
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 :)