我正在尝试追踪为什么字符串在我的应用程序中存储了这么久,并且吃掉了过多的内存。我有一个定期运行的Windows服务。
它从数据库中读取数据(以DataSet的形式),然后进行一些处理 - 所有托管的.NET。
Windows服务每5分钟左右触发一次,这会进行一些交叉引用。 DataSet的每一行都不应该花费超过一秒 - 最糟糕的情况!
私人字节的一个阶段> 1.2GB,即使没有可用于处理的数据。没有全局变量,所有处理都在各个方法中完成。
我拍了快照并用WinDbg处理。结果如下:
0:000> !dumpheap -min 85000
Address MT Size
02027f40 00166620 101432 Free
28411000 79330b24 536870936
48c11000 79333594 226273040
08411000 79330b24 452546504
total 4 objects
Statistics:
MT Count TotalSize Class Name
00166620 1 101432 Free
79333594 1 226273040 System.Byte[]
79330b24 2 989417440 System.String
Total 4 objects
因此我们希望找到导致问题的2个字符串:
0:000> !dumpheap -mt 79330b24 -min 85000
Address MT Size
28411000 79330b24 536870936
08411000 79330b24 452546504
total 2 objects
Statistics:
MT Count TotalSize Class Name
79330b24 2 989417440 System.String
Total 2 objects
现在我想找出这两个位置的位置,但是当我使用!gcroot时,它不会返回任何结果:
0:000> !gcroot 28411000
Note: Roots found on stacks may be false positives. Run "!help gcroot" for
more info.
Scan Thread 0 OSTHread 2970
Scan Thread 2 OSTHread 2ab4
Scan Thread 3 OSTHread 12ac
Scan Thread 4 OSTHread 1394
Scan Thread 5 OSTHread 1b78
Scan Thread 8 OSTHread 1364
Scan Thread 9 OSTHread 226c
Scan Thread 10 OSTHread 1694
0:000> !gcroot 08411000
Note: Roots found on stacks may be false positives. Run "!help gcroot" for
more info.
Scan Thread 0 OSTHread 2970
Scan Thread 2 OSTHread 2ab4
Scan Thread 3 OSTHread 12ac
Scan Thread 4 OSTHread 1394
Scan Thread 5 OSTHread 1b78
Scan Thread 8 OSTHread 1364
Scan Thread 9 OSTHread 226c
Scan Thread 10 OSTHread 1694
我不明白我做错了什么,或者为什么无法找到字符串的根。我已经完成了!做它,它只是说字符串是不可打印的:
0:000> !do 28411000
Name: System.String
MethodTable: 79330b24
EEClass: 790ed65c
Size: 536870930(0x20000012) bytes
(C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
String: <String is invalid or too large to print>
Fields:
MT Field Offset Type VT Attr Value Name
79332d70 4000096 4 System.Int32 0 instance 268435457 m_arrayLength
79332d70 4000097 8 System.Int32 0 instance 226273026 m_stringLength
79331804 4000098 c System.Char 0 instance 57 m_firstChar
79330b24 4000099 10 System.String 0 shared static Empty
>> Domain:Value 00159f38:01021198 <<
79331754 400009a 14 System.Char[] 0 shared static WhitespaceChars
>> Domain:Value 00159f38:010217d4 <<
和
0:000> !do 08411000
Name: System.String
MethodTable: 79330b24
EEClass: 790ed65c
Size: 452546502(0x1af94fc6) bytes
(C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
String: <String is invalid or too large to print>
Fields:
MT Field Offset Type VT Attr Value Name
79332d70 4000096 4 System.Int32 0 instance 226273243 m_arrayLength
79332d70 4000097 8 System.Int32 0 instance 226273242 m_stringLength
79331804 4000098 c System.Char 0 instance 45 m_firstChar
79330b24 4000099 10 System.String 0 shared static Empty
>> Domain:Value 00159f38:01021198 <<
79331754 400009a 14 System.Char[] 0 shared static WhitespaceChars
>> Domain:Value 00159f38:010217d4 <<
有人可以帮忙吗?
-
更新
!eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x01175764
generation 1 starts at 0x011756dc
generation 2 starts at 0x01021000
ephemeral segment allocation context: none
segment begin allocated size
01020000 01021000 0117b770 0x0015a770(1419120)
Large object heap starts at 0x02021000
segment begin allocated size
02020000 02021000 02040d88 0x0001fd88(130440)
28410000 28411000 48411018 0x20000018(536870936)
48c10000 48c11000 563db710 0x0d7ca710(226273040)
08410000 08411000 233a5fc8 0x1af94fc8(452546504)
Total Size 0x488d9be8(1217240040)
------------------------------
GC Heap Size 0x488d9be8(1217240040)
更新2:我删除了对XML的引用,因为这个特定程序不处理XML - 我的不好。
更新3:
以下是使用psscor2.dll的结果
0:000> !heapstat -inclUnrooted
Heap Gen0 Gen1 Gen2 LOH
Heap0 32780 68316 1324728 1217845888
Free space: Percentage
Heap0 12 67212 59764 101640 SOH: 8% LOH: 0%
Unrooted objects: Percentage
Heap0 2684 1104 757416 1217715448 SOH: 53% LOH: 99%
答案 0 :(得分:7)
EDITED (D'哦,需要更多咖啡)这些字符串大于85,000字节,因此它们将驻留在大型对象堆上,这很少被垃圾收集而不会被压缩(导致碎片,特别是如果你要分配大量短期大型物体)。
WinDbg告诉你的是正确的 - 这些没有root并且它们是垃圾,但是由于它们在LOH上,它们可能不会很快被清除(如果有的话)。
您肯定需要重新考虑如何处理XML,查看流入/流出数据,而不是预先在内存中加载/创建。
答案 1 :(得分:1)
只有在有内存压力时才会收集LOH中的对象。只有在进行完整收集时,GC才会收集LOH中的对象。
psscor2.dll(调试托管代码的扩展名)有一个命令
!HeapStat [-inclUnrooted | -iu]
与!eeheap
相比,只会转储有效的根