免费〜90%的Gen2 .NET堆

时间:2018-12-06 02:27:12

标签: .net garbage-collection out-of-memory windbg sos

我们正在尝试调试Windows托管服务上的内存泄漏。我得到了进程转储,并开始在windbg中进行分析。 Heapstat显示SOH中的~~ 90%内存是可用的,但是没有收集到垃圾。系统现在抛出OutOfMemory异常。

0:000> !heapstat
Heap             Gen0         Gen1         Gen2          LOH
Heap0      1280897288     14491488   3047752776      5809312
Heap1       363914880     15115160   4352729656      4666416
Heap2      1703707464     30418232   2747904232     12655040
Heap3       494016304     20954808   4365778560       800136
Total      3842535936     80979688  14514165224     23930904

Free space:                                                 Percentage
Heap0      1249220440      4930840   2915300544        48424SOH: 96% LOH:  0%
Heap1       331677752      4231032   4180971712          184SOH: 95% LOH:  0%
Heap2      1681027112      6764328   2612922440      2073728SOH: 95% LOH: 16%
Heap3       462287616      5282384   4230317520           88SOH: 96% LOH:  0%
Total      3724212920     21208584  13939512216      2122424

0:000> !EEHeap -gc
Number of GC Heaps: 4
------------------------------
Heap 0 (000001621d6173a0)
generation 0 starts at 0x0000016882f12f60
generation 1 starts at 0x0000016882141000
generation 2 starts at 0x000001621deb1000
ephemeral segment allocation context: none
         segment             begin         allocated              size
000001621deb0000  000001621deb1000  00000162d3941448  0xb5a90448(3047752776)
0000016882140000  0000016882141000  00000168cf4a2068  0x4d361068(1295388776)
Large object heap starts at 0x000001661deb1000
         segment             begin         allocated              size
000001661deb0000  000001661deb1000  000001661e43b4a0  0x58a4a0(5809312)
Heap Size:               Size: 0x10337b950 (4348950864) bytes.
------------------------------
Heap 1 (000001621d640760)
generation 0 starts at 0x0000016672c34480
generation 1 starts at 0x0000016671dca0e8
generation 2 starts at 0x000001631deb1000
ephemeral segment allocation context: none
         segment             begin         allocated              size
000001631deb0000  000001631deb1000  000001641deae150  0xffffd150(4294955344)
000001666e6b0000  000001666e6b1000  0000016688742b00  0x1a091b00(436804352)
Large object heap starts at 0x000001662deb1000
         segment             begin         allocated              size
000001662deb0000  000001662deb1000  000001662e324430  0x473430(4666416)
Heap Size:               Size: 0x11a502080 (4736426112) bytes.
------------------------------
Heap 2 (000001621d669bb0)
generation 0 starts at 0x0000016783e43538
generation 1 starts at 0x0000016782141000
generation 2 starts at 0x000001641deb1000
ephemeral segment allocation context: none
         segment             begin         allocated              size
000001641deb0000  000001641deb1000  00000164c1b4c0e8  0xa3c9b0e8(2747904232)
0000016782140000  0000016782141000  00000167e970b880  0x675ca880(1734125696)
Large object heap starts at 0x000001663deb1000
         segment             begin         allocated              size
000001663deb0000  000001663deb1000  000001663eac29c0  0xc119c0(12655040)
Heap Size:               Size: 0x10be77328 (4494684968) bytes.
------------------------------
Heap 3 (000001621d692760)
generation 0 starts at 0x000001698794b530
generation 1 starts at 0x000001698654f678
generation 2 starts at 0x000001651deb1000
ephemeral segment allocation context: none
         segment             begin         allocated              size
000001651deb0000  000001651deb1000  000001661de2a808  0xfff79808(4294416392)
0000016982140000  0000016982141000  00000169a506cc60  0x22f2bc60(586333280)
Large object heap starts at 0x000001664deb1000
         segment             begin         allocated              size
000001664deb0000  000001664deb1000  000001664df74588  0xc3588(800136)
Heap Size:               Size: 0x122f689f0 (4881549808) bytes.
------------------------------
GC Heap Size:            Size: 0x44c65d6e8 (18461611752) bytes.

我试着看一下小玩意儿,下面是结果。这些句柄数量巨大,但是现在我们陷入了如何进一步调试以找到根本原因的困境。

!gchandles
Handles:
    Strong Handles:       130
    Pinned Handles:       16
    Async Pinned Handles: 297
    Ref Count Handles:    88
    Weak Long Handles:    1261
    Weak Short Handles:   829
    SizedRef Handles:     8

大多数固定句柄是System.Object []或System.String [],但无助于找出根本原因。

000001621d541710 Pinned      000001661dfd7498   130584                  System.Object[]
000001621d541798 Pinned      000001661df214c0    65304                  System.Object[]
000001621d5417a0 Pinned      000001621deb1420       26                  System.String
000001621d5417a8 Pinned      000001621deb1420       26                  System.String
000001621d5417d0 Pinned      000001661deb9a30    32664                  System.Object[]
000001621d5417d8 Pinned      000001661deb5a38    16344                  System.Object[]
000001621d5417e0 Pinned      000001661deb3a20     8184                  System.Object[]
000001621d5417e8 Pinned      000001661deb35e8     1048                  System.Object[]
000001621d5417f0 Pinned      000001621deb1408       24                  System.Object
000001621d5417f8 Pinned      000001661deb1038     9616                  System.Object[]

是否有任何方法可以跟踪导致SOH碎片化并阻止该可用空间回收的原因?

我没有使用FinalizeQueue进行检查的对象。

1 个答案:

答案 0 :(得分:0)

  

Heapstat显示SOH中的~~ 90%的内存是可用的,但没有收集到垃圾。

如果没有进行垃圾收集,它将不是免费的。您是说“但没有被压实”吗?

执行!dumpheap -type Free以查看垃圾收集器已经收集了什么。

  

大多数固定句柄是System.Object []或System.String [],但无助于找出根本原因。

我要说的根本原因是固定的对象。您还想要什么根本原因?现在,您知道可以在代码审查中找到什么。如果有帮助,您还可以查看Object []以查看其内容。

如果要为每个对象进行堆栈跟踪,则需要专用的工具,例如JetBrains dotMemory。如果使用18 GB进行复制肯定会有点慢,所以应该尝试以较小的比例复制它。

  

是否有任何方法可以跟踪导致SOH碎片化并阻止该可用空间回收的原因?

由于固定对象,SOH碎片化。固定的物体会阻止SOH压实,从而留出通常不应放置的自由空间。

总而言之,寻找GCHandle.Alloc()并确保对每个对象都有一个Free()调用。