我们正在尝试调试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进行检查的对象。
答案 0 :(得分:0)
Heapstat显示SOH中的~~ 90%的内存是可用的,但没有收集到垃圾。
如果没有进行垃圾收集,它将不是免费的。您是说“但没有被压实”吗?
执行!dumpheap -type Free
以查看垃圾收集器已经收集了什么。
大多数固定句柄是System.Object []或System.String [],但无助于找出根本原因。
我要说的根本原因是固定的对象。您还想要什么根本原因?现在,您知道可以在代码审查中找到什么。如果有帮助,您还可以查看Object []以查看其内容。
如果要为每个对象进行堆栈跟踪,则需要专用的工具,例如JetBrains dotMemory。如果使用18 GB进行复制肯定会有点慢,所以应该尝试以较小的比例复制它。
是否有任何方法可以跟踪导致SOH碎片化并阻止该可用空间回收的原因?
由于固定对象,SOH碎片化。固定的物体会阻止SOH压实,从而留出通常不应放置的自由空间。
总而言之,寻找GCHandle.Alloc()
并确保对每个对象都有一个Free()
调用。