在捕获我们的一个.NET进程的性能监视指标时,我们注意到我们有大量的固定对象。具体来说,我们正在监控" .NET CLR内存" counter" 固定对象数"它的价值稳步上升到数千。总体而言,趋势是稳定的45度上升趋势线。由于这是一个可靠的可重复条件,我们使用WinDbg进行了内存转储,并且惊讶地发现我们只有23个固定项目与我们在PerfMon中看到的不匹配。这引出了以下问题:
为什么固定对象的PerfMon和GCHandles数量不同?
如果PerfMon是正确的,这不表示内存泄漏吗?如果是,我们如何找到它?
!gchandles
注意:所有"固定"句柄都是System.Object[]
,它们似乎都包含Int64值
Handles:
Strong Handles: 183
Pinned Handles: 23
Async Pinned Handles: 3
Ref Count Handles: 7
Weak Long Handles: 16762
Weak Short Handles: 481
SizedRef Handles: 8
Dependent Handles: 57
来自!eeheap -gc
0:048> !eeheap -gc
Number of GC Heaps: 4
------------------------------
Heap 0 (0000000001fe2e20)
generation 0 starts at 0x0000000103879b20
generation 1 starts at 0x000000010385f528
generation 2 starts at 0x00000000ff801000
ephemeral segment allocation context: none
segment begin allocated size
00000000ff800000 00000000ff801000 00000001038cfb38 0x40ceb38(67955512)
Large object heap starts at 0x00000004ff801000
segment begin allocated size
00000004ff800000 00000004ff801000 0000000501006c98 0x1805c98(25189528)
Heap Size: Size: 0x58d47d0 (93145040) bytes.
------------------------------
Heap 1 (0000000001fe7d50)
generation 0 starts at 0x0000000203d84328
generation 1 starts at 0x0000000203c58a70
generation 2 starts at 0x00000001ff801000
ephemeral segment allocation context: none
segment begin allocated size
00000001ff800000 00000001ff801000 0000000204c9a298 0x5499298(88707736)
Large object heap starts at 0x000000050f801000
segment begin allocated size
000000050f800000 000000050f801000 0000000510408e38 0xc07e38(12615224)
Heap Size: Size: 0x60a10d0 (101322960) bytes.
------------------------------
Heap 2 (0000000001ff9590)
generation 0 starts at 0x000000030360fb10
generation 1 starts at 0x00000003036065f0
generation 2 starts at 0x00000002ff801000
ephemeral segment allocation context: none
segment begin allocated size
00000002ff800000 00000002ff801000 00000003042ff190 0x4afe190(78635408)
Large object heap starts at 0x000000051f801000
segment begin allocated size
000000051f800000 000000051f801000 0000000520c38850 0x1437850(21198928)
Heap Size: Size: 0x5f359e0 (99834336) bytes.
------------------------------
Heap 3 (00000000020152b0)
generation 0 starts at 0x00000004036f9da8
generation 1 starts at 0x00000004036f9a28
generation 2 starts at 0x00000003ff801000
ephemeral segment allocation context: none
segment begin allocated size
00000003ff800000 00000003ff801000 00000004038c3da0 0x40c2da0(67906976)
Large object heap starts at 0x000000052f801000
segment begin allocated size
000000052f800000 000000052f801000 00000005305a1d88 0xda0d88(14290312)
Heap Size: Size: 0x4e63b28 (82197288) bytes.
------------------------------
GC Heap Size: Size: 0x1670eda8 (376499624) bytes.
答案 0 :(得分:4)
该perf计数器实际上并未显示钉扎手柄的数量。它显示上次垃圾回收期间无法移动的对象数。
这是一个非常不同的数字。首先,它当然是陈旧的,所以你的minidump不一定是一个很好的匹配。另一方面,它还显示了不需要手柄的针脚。在Windbg报告中,您无法轻易看到这些内容。它们是具有[pinned]属性的局部变量。垃圾收集器在执行堆栈遍历时找回它们,这是一种非常有效的引脚方式。 C#中的 fixed 关键字创建它们。
看到这些类型的引脚增长,我能想到的可能原因有限。递归可以解释它。或者线程数越来越多,这是造成内存爆炸问题的常见原因。