WinDbg没有告诉我字符串的根源所在

11

我正在尝试查找我的应用程序中为什么会存储一个字符串这么长,导致过多的内存消耗。我有一个定期运行的Windows服务。

它从数据库(以DataSet形式)读取数据,然后进行一些处理 - 全部由.NET管理。

Windows服务每5分钟触发一次,进行交叉引用。数据集的每一行最坏情况下不应该超过一秒钟!

在某个阶段,即使没有可处理的数据,私有字节> 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

所以我们要找出导致问题的两个字符串:

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

我不明白我做错了什么,或者为什么找不到字符串的根。我已经对它执行了!do操作,但它只是说这些字符串无法打印:

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%

你是如何拥有一个大小为 512 MB 的字符串值的?你可以使用 XMLReader 来读取数据吗? - Bharath K
2个回答

7
已编辑(需要更多咖啡)这些字符串的大小超过85,000字节,因此它们将驻留在大对象堆上,该堆很少进行垃圾回收并且不紧凑(导致碎片化,特别是如果您正在分配许多短暂的大对象)。
WinDbg告诉您的是正确的 - 这些字符串没有根,并且它们是垃圾,但由于它们在LOH上,它们可能不会快速清除(如果有的话)。
您肯定需要重新考虑如何处理XML,尝试流式传输数据而不是预先在内存中加载/创建。

那么你是说任何驻留在 LOH 上的对象都无法使用 WinDBG 找到吗?因为我有一个 226MB 的字节数组,我也不确定该如何处理。 - Dominic Zukiewicz
我已经重新编辑了我的答案,因为我意识到我关于LOH(大对象堆)没有被收集(它没有被压缩)的说法是无稽之谈。就我所看到的情况而言,WinDBG 可以很好地在 LOH 上找到对象,问题在于垃圾对象不能快速地被收集,因为它们在 LOH 上,你最新的更新清晰地显示了这一点。 - Paolo
所以当我们说未根的时候,我们只是指那些不再被引用的对象,但在我的情况下它们还没有被垃圾回收? - Dominic Zukiewicz

1

只有在内存压力下,LOH 中的对象才会被回收。GC 仅在执行完整的垃圾回收时才会收集 LOH 中的对象。

psscor2.dll(用于调试托管代码的扩展)具有一个命令

!HeapStat [-inclUnrooted | -iu]

这将仅转储有效的根,与!eeheap相比。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接