tags:

views:

122

answers:

2

Hello,

I have used the following sos command to enumerate all instances of a particular type in a running asp application (hosted on windows xp 4 GB machine).

.foreach (obj { !dumpheap -type ::my type:: -short ::start of address space:: ::end of address space:: }) { !objsize ${obj} }.

This enumerates all objects of the given type in gc gen2.

The object size on an average seems to be around 500 KB and there are around 2000 objects. This alone adds up to around 1 GB of memory whereas my asp-process memory in task manager shows only around 700 MB. One more point is that I haven't considered other loaded objects I am using.

Also all the above objects are root objects that will not be garbage collected. Not sure if this command is wrong or if there is any other explanation for this mismatch in size that sos returns and what is shown in task manager?

Thanks in advance,
Bharath K.

+3  A: 

!objsize calculates the size of an instance including all its referenced objects, so if you have any objects that share references to other objects the size of these will be counted multiple times. The most common source for this is probably strings, as literal strings are interned and thus shared among objects using the same literal text. However, you may also have collections referencing the same objects. In any case, the sum will be incorrect unless the counted objects do not share any references at all.

Consider this example

class SomeType {
    private readonly string Text;

    public SomeType(string text) {
        Text = text;
    }
}

and this code

var st1 = new SomeType("this is a long string that will be stored only once due to interning");
var st2 = new SomeType("this is a long string that will be stored only once due to interning");

In WinDbg

0:006> !dumpheap -type Some
 Address       MT     Size
00ceb44c 00b738a8       12     
00ceb458 00b738a8       12     

0:006> !objsize 00ceb44c
sizeof(00ceb44c) =          164 (        0xa4) bytes (TestApp.SomeType)
0:006> !objsize 00ceb458
sizeof(00ceb458) =          164 (        0xa4) bytes (TestApp.SomeType)

0:006> !DumpObj 00ceb44c
Name:        TestApp.SomeType
MethodTable: 00b738a8
EEClass:     00b714bc
Size:        12(0xc) bytes
File:        c:\dev2010\FSharpLib\TestApp\bin\Release\TestApp.exe
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
79b9d2b8  4000001        4        System.String  0 instance 00ceb390 Text
0:006> !DumpObj 00ceb458
Name:        TestApp.SomeType
MethodTable: 00b738a8
EEClass:     00b714bc
Size:        12(0xc) bytes
File:        c:\dev2010\FSharpLib\TestApp\bin\Release\TestApp.exe
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
79b9d2b8  4000001        4        System.String  0 instance 00ceb390 Text

As you can see from the output of !dumpobj, they both share the same reference, so if you sum the size as reported by !objsize above, the string is counted twice.

Brian Rasmussen
Thanks Rasmussen, Each of my object contains an distinct xml document constructed from the definition of the form(string) which is unique by nature. Again thanks for the great insight. I will verify once again if the strings are indeed being interned and marked this question as closed if this is happening.
Bharath K
A: 

Thanks Rasmussen,
Interning of values was the reason for the mismatch between objsize shown in sos and what I get in task manager. The following code sample also indicates interning of string values.

        string str1 = "this is a long string that will be stored only once due to interning";
        string str2 = "this is a long string that will be stored only once due to interning";

        Console.WriteLine( string.ReferenceEquals( str1, str2 ) ); // This returns true...

The true value for reference equals check indicates interning here.

Thanks,
Bharath K

Bharath K