w3wp.exe 垃圾堆充满了自由对象 space 并且还在继续增长

w3wp.exe Garbage Heap is FULL of Free object space and keeps on growing

我的 IIS 应用程序(.NET 4.0、IIS7)的内存不断增长,最终崩溃,好像我有内存泄漏。

所以我拿了一个 DMP,当时它大约有 1.7GB,并在 WinDbg 中打开它。

dumpheap -stat 命令显示虽然我在堆中有相当数量的对象,但大多数(以及在查看顺序 DMP 时正在增长的位)被标记为 "Free"(>800MB) :

000007feef55b768 46091 2212368 System.Data.DataRowView
000007fe9739dda8 10355 2236680 Newtonsoft.Json.Serialization.JsonProperty
000007fef4260610 33062 2644960 System.Signature
000007fef4242250 41809 4682608 System.Reflection.RuntimeMethodInfo
000007fef424f058 69232 8847997 System.Byte[]
000007fef4241b28 11 9437680 System.Double[]
000007fef4237ca0 15 9505176 System.DateTime[]
000007fef424c168 32559 11009308 System.Char[]
000007fef424dc30 17271 11795376 System.Int32[]
000007feef555c48 908 17936672 System.Data.RBTree`1+Node[[System.Int32, mscorlib]][]
000007feef554f58 853 22056952 System.Data.RBTree`1+Node[[System.Data.DataRow, System.Data]][]
000007feef5514b0 541444 51978624 System.Data.DataRow
000007fef424aee0 1550958 132599872 System.String
000007fef422f1b8 183607 178409288 System.Object[]
0000000000d8b2d0 234017 844500226 Free

然后我 运行 “!dumpheap -type Free” 给了我一个 lot 微小的免费对象(准确地说是每个 94 字节!)最后是几个更大的 "Free" 对象:

00000003098a59b0 0000000000d8b2d0 134 Free
00000003098c19d0 0000000000d8b2d0 102 Free
00000003098ffa00 0000000000d8b2d0 54 Free
0000000309a41d98 0000000000d8b2d0 5961750 Free
000000041f8a1000 0000000000d8b2d0 24 Free
000000042001b4d0 0000000000d8b2d0 16933078 Free
00000004211bf7c8 0000000000d8b2d0 7702 Free
00000004212c1600 0000000000d8b2d0 35173374 Free
00000004236b3be0 0000000000d8b2d0 66886 Free
0000000423cc41e8 0000000000d8b2d0 10778318 Free
0000000424768928 0000000000d8b2d0 2254734 Free
00000004249ec128 0000000000d8b2d0 21166350 Free
000000042600f1e0 0000000000d8b2d0 51366 Free
000000042621bac8 0000000000d8b2d0 114007238 Free

Statistics:
              MT    Count    TotalSize Class Name
000007fef31e7460        1           32 System.Net.SafeLocalFree
0000000000d8b2d0   234017    844500226      Free
Total 234018 objects

注意 "d8b2d0" 的重复地址 I 运行 a "!gcroot d8b2d0" 我得到以下结果:

0:000> !gcroot d8b2d0
Found 0 unique roots (run '!GCRoot -all' to see all roots).

所以...毕竟...我有大量空闲对象卡在我的堆上,GC 没有释放。这会累积约 2-3 小时。没有其他迹象表明实际类型化对象有任何内存泄漏。它发生在我们生产中的几乎所有 VM 上。

有谁知道如何处理 GC 在堆上留下如此多的空闲对象 space?

它让我 运行 围观了好几天。向能帮我解决这个问题的天才致敬!

如果您确定您的应用存在内存泄漏,我建议您使用内存分析器开始本地分析。这可能比分析生产中的内存转储更快地揭示问题的根源。

感谢 magicandre1981 关于使用 PerfView 的建议,在大量内存转储之后,我将这个问题归结为在 Linq 中使用 DataRow.DefaultIfEmpty()表达。它是在两个数据表之间执行 LeftJoin 的支持函数的一部分。

通过将 DataRow 枚举中的 DefaultIfEmpty() 作为 Linq 表达式的一部分,我可以在几分钟内重新创建飙升至 4GB+ 的内存空间。其中大部分通过创建大量的 ItemArrayObjects(包括小型和大型对象堆)一直存在到 Gen2 GC 收集。这反过来导致不断攀升的承诺记忆价值。 GC2 收集跟不上小堆,大堆的重用率很低(如果有的话)。

我们已经取消了此调用,并且相同的游戏在提交的内存中永远不会超过 50MB。我们现在需要看看这对我们的 DataTable 连接有什么影响,但是内存堆之谜已经解开了!

感谢大家的帮助。