如何解决Gen2堆碎片问题

时间:2017-11-24 21:40:35

标签: c# .net garbage-collection memory-fragmentation heap-fragmentation

我正在运行一个为HTTP请求提供服务的C#应用​​程序。我最近注意到它占据了我预期的更多内存。我抓住了一些转储,在Windbg中弹出它们,发现大部分内存被标记为Free:

!dumpheap -stat
...
00007ffde4783630   681599     65433504 System.Threading.Tasks.TaskFactory+CompleteOnInvokePromise
00007ffde47cc988   167885     76872908 System.Byte[]
00007ffde47c6948   521353     80352802 System.String
0000007e3a16c2d0  1870425   1415374334      Free

所以转储大约是3GB,所以大约一半是可用内存。看着堆,我看到了:

!heapstat
Heap             Gen0         Gen1         Gen2          LOH
Heap0        82248472      7354560    987275056    178834656
Heap1        93146552      6382864    857470096    129435960
Total       175395024     13737424   1844745152    308270616

Free space:                                                 Percentage
Heap0        40969256       146456    640426720     54829792 SOH: 63% LOH: 30%
Heap1        75943736        94448    550812312     54825216 SOH: 65% LOH: 42%
Total       116912992       240904   1191239032    109655008

所以我的小物件堆很碎片,特别是Gen2。在服务器上我可以看到gen2集合正在发生(使用性能计数器),但即使它们看起来像gen2堆也没有被压缩。即使服务器上只有1-2%的RAM可用,也不会压缩gen2堆。

对我来说,看起来我正在遭受这种记忆压力,因为堆是碎片。但是,我无法弄清楚碎片发生的原因或者为什么gen2无法压缩。一些自由空间的大小为6MB,所以我认为它肯定会压缩那些空间。

任何人都可以给我一些关于如何弄清楚我的堆如此碎片化的想法吗?我甚至在这里咆哮着正确的树吗?

非常感谢任何帮助,谢谢!

编辑1:

!gchandles的细分是:

Handles:
Strong Handles:       4507
Pinned Handles:       58
Async Pinned Handles: 977
Ref Count Handles:    1
Weak Long Handles:    6087
Weak Short Handles:   724

1 个答案:

答案 0 :(得分:0)

下一步是使用!gchandles并查找固定句柄。这可能会识别锁定到特定内存位置的对象,因为某些本机代码(例如C ++)需要访问它。虽然垃圾收集可能会在内存中移动对象,但.NET不会更新C ++指针,因此固定是唯一的选择。

  

即使服务器上只有1-2%的RAM可用,也不会压缩gen2堆。

你在这里谈论物理RAM。从操作系统来看,我认为它尽可能使用可用资源,所以我期望 RAM始终100%使用。如果"未使用",我希望操作系统将其用于缓存。因此,物理RAM使用率实际上不能成为垃圾收集的指标。

另外,我不会太担心。如果.NET没有使用该内存,它将被操作系统交换到磁盘,因此可以将物理RAM用于其他目的。