隔离大量固定对象的来源 [英] Isolating source of large pinned object count

查看:78
本文介绍了隔离大量固定对象的来源的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在为我们的一个.NET流程捕获性能监视指标时,我们注意到我们有大量固定的对象.具体来说,我们正在监视" .NET CLR内存"计数器"固定对象的数量",该计数器的价值稳步上升到数千.通常,趋势是稳定的45度上升趋势线.由于这是一个可靠的可重复条件,因此我们使用WinDbg进行了内存转储,并惊讶地发现我们只有23个固定的项与我们在PerfMon中看到的不匹配.这导致我们提出以下问题:

While capturing Performance Monitoring metrics for one of our .NET processes we noticed that we had a large number of pinned objects. Specifically, we were monitoring the ".NET CLR Memory" counter "# of Pinned Objects" which steadily rose in value into the thousands. In general the trend is a steady 45 degree upward trend line. Since this is a reliably repeatable condition we took a memory dump with WinDbg and were surprised to find that we only had 23 pinned items which did not match what we saw in PerfMon. This led us to the following questions:

  1. 为什么固定对象的PerfMon和GCHandles计数不同?

  1. Why is the PerfMon and GCHandles count of pinned objects different?

如果PerfMon是正确的,这是否表示内存泄漏?如果是,我们如何找到它?

If PerfMon is correct doesn't this indicate a memory leak? If yes, how can we locate it?

!gchandles

注意:所有固定"句柄都是System.Object[],它们似乎都包含Int64值

Note: all the "Pinned" handles are all System.Object[] which all appear to contain Int64 values

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.

推荐答案

该perf计数器实际上并不显示固定句柄的数量.它显示上一次垃圾回收期间无法移动的对象数.

That perf counter doesn't actually display the number of pinning handles. It displays the number of objects that could not be moved during the last garbage collection.

这是一个非常不同的数字.首先,这当然是陈旧的,因此您的小型转储不一定是理想的选择.另外,它还显示不需要手柄的销钉.您很难在Windbg报告中轻松看到这些内容.它们是具有[固定]属性的局部变量.垃圾收集器在执行堆栈遍历时会找到它们,这是一种非常非常有效的固定方法. C#中的 fixed 关键字创建它们.

Which is a very different number. For one it is stale of course so your minidump is not necessarily a good match. For another, it also shows pins that don't require a handle. You can't easily see those back in the Windbg report. They are local variables that have the [pinned] attribute. The garbage collector finds them back when it performs a stack walk, a very efficient way to pin. The fixed keyword in C# creates them.

看到这些种类的针脚增长,我能想到的可能原因数量有限.递归可以解释它.或线程数量不断增加,这是导致内存爆炸问题的常见原因.

Seeing those kinds of pins grow has a limited number of possible causes that I can think of. Recursion can explain it. Or an ever increasing number of threads, a common cause for memory explosion trouble.

这篇关于隔离大量固定对象的来源的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆