Actually it shows that the one and only instance is referenced twice. Notice the values in the leftmost column differ. It could be different registers or different parts of the stack frame which point to the same instance.
In my experience this happens quite often (especially with debug builds). !dso
is useful for locating objects and in that case the important column is the Object column, which holds the actual references.
E.g. if I run your example above from the debugger and place a break point on Main the output from dso
looks like this just before the Main method returns.
0:000> !dso
OS Thread Id: 0x1944 (0)
ESP/REG Object Name
eax 0240b2e0 TestApp.Program+MyClass
ecx 0240b2e0 TestApp.Program+MyClass
0014F224 0240b2d0 System.Object[] (System.String[])
0014F3CC 0240b2d0 System.Object[] (System.String[])
0014F400 0240b2d0 System.Object[] (System.String[])
As you can see both the eax
and the ecx
registers hold a reference to the instance despite the fact that the C# source only has a single reference.
If you look at the JIT compiled code for Main it looks like this
0:000> !u 00200070
Normal JIT generated code
TestApp.Program.Main(System.String[])
Begin 00200070, size 46
C:\dev2010\TestApp\TestApp\Program.cs @ 33:
>>> 00200070 55 push ebp
00200071 8bec mov ebp,esp
00200073 83ec14 sub esp,14h
00200076 33c0 xor eax,eax
00200078 8945f4 mov dword ptr [ebp-0Ch],eax
0020007b 8945f8 mov dword ptr [ebp-8],eax
0020007e 894dfc mov dword ptr [ebp-4],ecx
00200081 833d3c31150000 cmp dword ptr ds:[15313Ch],0
00200088 7405 je 0020008f
0020008a e8c05ac268 call clr!JIT_DbgIsJustMyCode (68e25b4f)
0020008f 33d2 xor edx,edx
00200091 8955f0 mov dword ptr [ebp-10h],edx
00200094 90 nop
C:\dev2010\TestApp\TestApp\Program.cs @ 35:
00200095 b960391500 mov ecx,153960h (MT: TestApp.Program+MyClass)
0020009a e8811ff4ff call 00142020 (JitHelp: CORINFO_HELP_NEWSFAST)
0020009f 8945ec mov dword ptr [ebp-14h],eax
002000a2 8b4dec mov ecx,dword ptr [ebp-14h]
002000a5 ff158c391500 call dword ptr ds:[15398Ch] (TestApp.Program+MyClass..ctor(), mdToken: 06000003)
002000ab 8b45ec mov eax,dword ptr [ebp-14h]
002000ae 8945f0 mov dword ptr [ebp-10h],eax
C:\dev2010\TestApp\TestApp\Program.cs @ 36:
002000b1 90 nop
002000b2 8be5 mov esp,ebp
002000b4 5d pop ebp
002000b5 c3 ret
Notice the instruction call 00142020
. This creates the instance of MyClass
and returns the reference in the eax
register. Following that the reference is stored at dword ptr [ebp-14h]
.
The next instruction reads the value stored at dword ptr [ebp-14h]
and stores the value in the ecx
register, which is then used as input for the call to the constructor call dword ptr ds:[15398Ch] (TestApp.Program+MyClass..ctor(), mdToken: 06000003)
.
This explains why dso
lists the reference twice in this case. However, you rarely need to go into the details about this when debugging.