String.Format and garbage collection

In my current research on high CPU usage in our application, I find that GC takes up most of the CPU time. Looking at the memdump of the w3wp process (the application is an iis host) I found something strange: there were many 46 byte large strings in the heap, all dead and ready to be collected. Examine the following command:

!dumpheap -mt 00007ff9bd160e08 -dead -min 2e -max 2e

      

Which dumps out all 46 size dead line objects told me that I currently have 260,000 dead lines of this size. Looking inside, some of them quickly showed that they all come from the same place, a helper method that creates keys for our cache:

private static string Key(Guid ssoId)
{
    return string.Format("BasicUser:{0}-Brand:{1}", ssoId, MemBag.Client.BrandEnum);
}

      

The 46 byte string is "BasicUser:" at most, at least as far as I can see:

0:000> !do 000000f1d48d49a0
Name:        System.String
MethodTable: 00007ff9bd160e08
EEClass:     00007ff9bca84860
Size:        46(0x2e) bytes
File:        C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
String:      BasicUser:
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
00007ff9bd163980  40000ab        8         System.Int32  1 instance               10 m_stringLength
00007ff9bd1620f0  40000ac        c          System.Char  1 instance               42 m_firstChar
00007ff9bd160e08  40000ad       18        System.String  0   shared           static Empty
                                 >> Domain:Value  000000ee12ced200:NotInit  000000ee138a4440:NotInit  <<

      

All these distributions seem to cause not only gen0 collections but many complete collections, about 80-90% of the collections are complete collections!

The method is indeed called a lot, but it doesn't make any sense that it puts such pressure on the GC! What's going on here? Is the method not implemented correctly? how do you get the string on the heap "BasicUser:"? where is the rest of the line? even with empty parameters, the "Brand" part is still missing.

I am very puzzled about this issue and really need some input here, any help is greatly appreciated!

Update

It seems to be always 10 characters long, I changed the code to:

  return string.Format("BasicUsr:{0}-Brand:{1}", ssoId, MemBag.Client.BrandEnum);

      

Changing User -> Usr, the result is that now I see lines like this on the heap: "BasicUsr: b" It seems to be the first 10 characters always, am I flushing the line wrong?

Update 2

I had a chance to get a 1 minute first grab from a live server, this is what I got, and if I read it correctly, we are allocating a huge amount of data, which causes high memory pressure, almost every gen2 collection

Hard working GC

+3


source to share


1 answer


Maybe there is a second generation object that references these strings, one that stores the return values โ€‹โ€‹of this method in a local field / variable on the stack?

A Gen 0 object will NOT be collected in a Gen 0 collection if referenced and promoted. If you create short live objects, then even for a very short period of time, Gen 2 objects are referenced, which are immediately promoted during the assignment itself.

In short, I would take the following steps:



in windbg, run it! dumpheap -type "System.String" -live

the -live switch will filter referenced objects.

Pick some fixed size objects you are talking about and call! gcroot [objAddr] where [objAddr] is the address of the String object. You will most likely find an object temporarily holding short live strings.

0


source







All Articles