约50%的.NET堆可用对象。如何知道是什么导致OOM

cra*_*ice 5 .net garbage-collection out-of-memory sos sosex

我试图确定是什么导致我的应用程序高内存使用率。所以我拿了进程转储文件。EEHeap命令显示.NET内存堆中大约有2.8 GB。

0:000> !EEHeap -gc
Number of GC Heaps: 2
------------------------------
Heap 0 (00000000001e3030)
generation 0 starts at 0x00000000a5f21360
generation 1 starts at 0x00000000a5c45a60
generation 2 starts at 0x000000007fff1000
ephemeral segment allocation context: none
 segment     begin allocated  size
000000007fff0000  000000007fff1000  00000000beeca248  0x3eed9248(1055756872)
Large object heap starts at 0x000000027fff1000
 segment     begin allocated  size
000000027fff0000  000000027fff1000  000000028f7d42f8  0xf7e32f8(259928824)
Heap Size:               Size: 0x4e6bc540 (1315685696) bytes.
------------------------------
Heap 1 (00000000001ed9e0)
generation 0 starts at 0x00000001a6c77908
generation 1 starts at 0x00000001a69a8370
generation 2 starts at 0x000000017fff1000
ephemeral segment allocation context: none
 segment     begin allocated  size
000000017fff0000  000000017fff1000  00000001cc127e58  0x4c136e58(1276341848)
Large object heap starts at 0x000000028fff1000
 segment     begin allocated  size
000000028fff0000  000000028fff1000  000000029b55d8f8  0xb56c8f8(190236920)
Heap Size:               Size: 0x576a3750 (1466578768) bytes.
------------------------------
GC Heap Size:            Size: 0xa5d5fc90 (2782264464) bytes.
Run Code Online (Sandbox Code Playgroud)

奇怪的是,最大的条目!Dumpheap是免费的,它消耗约1.3 GB

00000000001ac980      388   1373069656      Free
Run Code Online (Sandbox Code Playgroud)

其中一些在LOH中。

0:000> !dumpgen 3 -stat
       Count      Total Size      Type
-------------------------------------------------
           2        233,376   System.Collections.Hashtable+bucket[]
           1        262,168   System.Double[]
           6      1,804,496   System.Int64[]
           1      1,868,972   System.Int32[]
          57     18,707,978   System.Byte[]
          31     69,830,576   System.Object[]
         102    346,151,516   **** FREE ****
Run Code Online (Sandbox Code Playgroud)

没有准备好终结的对象,告诉我Finalize线程刚刚完成工作。

0:000> !FinalizeQueue
SyncBlocks to be cleaned up: 0
Free-Threaded Interfaces to be released: 0
MTA Interfaces to be released: 0
STA Interfaces to be released: 0
----------------------------------
------------------------------
Heap 0
generation 0 has 2748 finalizable objects (00000000047b6518->00000000047bbaf8)
generation 1 has 55 finalizable objects (00000000047b6360->00000000047b6518)
generation 2 has 6878 finalizable objects (00000000047a8c70->00000000047b6360)
Ready for finalization 0 objects (00000000047bbaf8->00000000047bbaf8)
------------------------------
Heap 1
generation 0 has 69 finalizable objects (0000000004807160->0000000004807388)
generation 1 has 6 finalizable objects (0000000004807130->0000000004807160)
generation 2 has 7818 finalizable objects (00000000047f7ce0->0000000004807130)
Ready for finalization 0 objects (0000000004807388->0000000004807388)
Run Code Online (Sandbox Code Playgroud)

LOH似乎非常分散。

0:000> !HeapStat
Heap             Gen0         Gen1         Gen2          LOH
Heap0       419073768      2996480    633686624    259928824
Heap1       625673552      2946456    647721840    190236920
Total      1044747320      5942936   1281408464    450165744

Free space:                                                 Percentage
Heap0       397468560           24      1545984    183287672SOH: 37% LOH: 70%
Heap1       611153984           24     16750104    162864048SOH: 49% LOH: 85%
Total      1008622544           48     18296088    346151720
Run Code Online (Sandbox Code Playgroud)

我不知道是否要在此处连接所有点,但是我的想法是,在下一个GC中,所有可用对象都将从内存中删除,.NET堆内存应基于Gen 0中的可用对象而下降, 1、2(因为它们将被压缩)。这是一个公正的声明,还是您看到我可能遗漏的任何其他问题?当然,LOH碎片是一个问题,但我不知道该占多少应用程序利用率。

编辑: Applicaton现在开始因OOM失败。根据下面的一些评论,针对Free对象报告的内存不会返回到OS。我怎么知道是什么导致OOM

Sas*_*ein 3

大对象堆不进行自动碎片整理,因此当 LOH 上有大量可用空间时,确实有可能出现 OOM。没有简单的方法可以摆脱这个洞。一般有以下三种方法:

1) 减少应用程序执行的 LOH(>85,000 字节)分配量,池化大型对象而不是让它们被收集,并尝试执行少量非常大的分配而不是大量中等分配。

2)使用.NET 4.5.1的LOH压缩。这是权宜之计,不是真正的解决方案,但如果碎片是您遇到的唯一与内存相关的问题,那么它现在可以提供帮助。

3) 迁移至 64 位进程。你仍然会遇到碎片问题,但你不会那么容易耗尽内存。