【问题标题】:w3wp.exe Garbage Heap is FULL of Free object space and keeps on growingw3wp.exe 垃圾堆充满了可用对象空间并不断增长
【发布时间】:2015-05-14 09:26:15
【问题描述】:

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

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

dumpheap -stat 命令显示,虽然我在堆中有相当数量的对象,但大多数(以及在查看顺序 DMP 时正在增长的位)被标记为“空闲”(>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 免费

然后我运行“!dumpheap -type Free”,它给了我 很多 个微小的 Free 对象(准确地说是每个 94 字节!),最后还有几个更大的“Free”对象:

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

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

注意到“d8b2d0”的重复地址,我运行了“!gcroot d8b2d0” 我得到了以下结果:

0:000> !gcroot d8b2d0
找到 0 个唯一根(运行 '!GCRoot -all' 以查看所有根)。

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

有人知道如何处理 GC 在堆上留下这么多空闲对象空间吗?

这让我好几天都在转圈。所以向能帮助我解决这个问题的天才致敬!

【问题讨论】:

  • 这是一个 Asp.Net 应用程序吗?使用了任何特定的框架或库?
  • 是的,它是 asp.net。它主要是 DataTables 和一些使用 net.pipe 的本地 WCF。
  • 你有没有互操作代码或者直接分配GCHandles的代码?我在想,也许你有很多 pinned 对象会阻止压缩。
  • 我认为这可能是问题所在,但我决心确切地发现源是什么......数据表(或者更具体地说,某种使用方式)或 WCF 或其他东西!? simple-talk.com/dotnet/.net-framework/…
  • 使用 PerfView 并选择“从转储中获取堆快照”。现在在 PerfView 中打开生成的 gcdump 文件以查看更好的概览:microsoft.com/en-us/download/details.aspx?id=28567

标签: memory-leaks garbage-collection heap-memory w3wp.exe


【解决方案1】:

感谢magicandre1981 提出的使用 PerfView 的建议,并且在进行了很多非常大的内存转储之后,我将此问题归结为在 Linq 表达式中使用 DataRow.DefaultIfEmpty()。它是在两个 DataTable 之间执行 LeftJoin 的支持函数的一部分。

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

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

感谢大家的帮助。

【讨论】:

  • 你能说明你为得出这个结论所采取的步骤吗?在非常相似的情况下,我正在努力寻找原因。
  • 首先下载并学习如何获取托管代码的内存转储文件。有更广泛的设置可以在发生崩溃或超出性能限制时触发它们,但我只是在我的应用程序启动时(然后在它膨胀时再次)将调试器附加到我的应用程序并创建快照内存转储。 docs.microsoft.com/en-us/windows-hardware/drivers/debugger/…
  • 然后,我将内存转储加载到 PerfView(如上所述),并且很容易浏览对象。将第一个快照与后一个快照进行比较,您会开始看到某些类型的对象导致内存膨胀的模式。
  • 在网络上的某个地方,我找到了有关哪些类型的对象会导致最多“生存”问题的指南,即使它们不再被认为是在使用中,它们也会持续存在于 GC2 中。好吧,我发现当您在 DataRow 上使用 DefaultIfEmpty 时,它会创建一个临时 ItemArrayObjects 对象,该对象永远不会被标记为死,因为它与 DataRow 相关联,依次是 DataTable 和 DataSet - 所以直到我处理掉我的数据集,该调用将产生更多幸存的垃圾。
  • 至于在你的代码中找到那个热点,它需要一些试验和错误来删除调用和隔离通货膨胀。我会说它识别出 ItemArrayObjects 是垃圾的来源,这导致我发现 DefaultIfEmpty() 调用可能是罪魁祸首,因为我自己没有在代码中对这种类型的对象做任何事情,因此,它必须与 DataRow 相关。
【解决方案2】:

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

【讨论】:

  • 感谢您的建议。我经历过这一切。没有内存泄漏,这导致我改为调查内存 DMP 文件。从上面的分析,它证实(我相信)确实没有内存泄漏。否则,那个 800MB 以上的大块将具有 gcroot 或至少具有某种对象类型。相反,它实际上被标记为 free 但 GC 就是不会释放它!?
猜你喜欢
  • 2019-08-08
  • 1970-01-01
  • 2019-03-18
  • 1970-01-01
  • 2012-01-20
  • 2015-01-15
  • 2013-03-10
  • 2021-01-20
  • 1970-01-01
相关资源
最近更新 更多