在我对我们的应用程序中高CPU使用率的持续调查中,我得出的结论是GC占用了大部分CPU时间。 看一下w3wp进程的memdump(应用程序是iis托管的)我发现了一些奇怪的东西:堆上有很多46字节的大字符串对象,它们都已经死了并准备收集。 进一步调查以下命令:
!dumpheap -mt 00007ff9bd160e08 -dead -min 2e -max 2e
将所有大小为46的死字符串对象转储出来告诉我,我目前有260000个这种大小的死字符串。查看其中的一些内容很快就会发现所有这些都来自同一个地方,这是一种为我们的缓存创建密钥的辅助方法:
private static string Key(Guid ssoId)
{
return string.Format("BasicUser:{0}-Brand:{1}", ssoId, MemBag.Client.BrandEnum);
}
46byte字符串是“BasicUser:”,仅此而已,至少就我所见:
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 <<
所有这些分配似乎不仅导致gen0集合,而且还有很多完整的集合,大约80-90%的集合是完整的集合!
该方法确实被调用了很多,但它对GC施加如此大的压力毫无意义!这里发生了什么?方法实施方式不好吗?为什么堆上的字符串“BasicUser:”?字符串的其余部分在哪里?即使有空的参数,“品牌”部分仍然缺失。
我对这个问题非常困惑,真的需要一些输入,非常感谢任何帮助!
似乎总是10个字符长,我将代码更改为:
return string.Format("BasicUsr:{0}-Brand:{1}", ssoId, MemBag.Client.BrandEnum);
更改用户 - &gt; Usr,结果是我现在在堆上看到这样的字符串:“BasicUsr:b”它似乎总是10个第一个字符,我是否将字符串转出错了?
我有机会从实时服务器获取1分钟的perfview捕获,这是我得到的,如果我正确读取它,我们分配了大量的数据,这是高内存压力的原因,几乎每个集合是gen2