7

我正在运行一个为 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
4

1 回答 1

0

The next step would be to use !gchandles and look for pinned handles. This might identify objects that are locked to a specific memory position, because some native code (e.g. C++) needs to access it. While garbage colelction may move objects around in memory, the C++ pointer will not be updated by .NET, so pinning is the only option.

Even when there is only 1-2% of RAM available on the server the gen2 heap is not being compacted.

You're talking about physical RAM here. From an operating system, I expexct that it uses the available resources as good as possible, so I expect the RAM to be 100% used at all the time. If it is "not used", I expect the OS to use it for caching. Due to this, the physical RAM usage cannot really be an indicator for garbage collection.

Also, I would not worry too much. If the memory is not used by .NET, it will be swapped to disk by the OS and thus free physical RAM for other purposes.

于 2017-11-25T15:50:31.747 回答