在我们的ASP.NET网络应用程序中,我们正在经历一个相当广泛的内存泄漏,我正在调查。使用WinDbg我得到了我们应用程序中最大的内存消费者(在WinDbg控制台中运行!dumpheap -stat
来获取这些):
MethodTable Addr Count Overall size Type
...
000007fee8306e10 212928 25551360 System.Web.UI.LiteralControl
000007feebf44748 705231 96776168 System.Object[]
000007fee838fd18 4394539 140625248 System.Web.Caching.CacheDependency+DepFileInfo
000007fee838e678 4394614 210941472 System.Web.FileMonitorTarget
000007feebf567b0 18259 267524784 System.Collections.Hashtable+bucket[]
00000000024897c0 1863 315249528 Free
000007feebf56cd0 14315 735545880 System.Byte[]
000007feebf4ec90 1293939 1532855608 System.String
据我所知,大量String
个物体可能很正常;仍有绝对的改进空间。但真正让我感到惊讶的是System.Web.FileMonitorTarget
个对象的数量:我们在堆上有超过400万个实例(48个字节)!使用两个内存转储并比较它们我发现这些对象没有被GC清理。
我想知道的是:这些物品来自哪里?我已经尝试过ANTS Memory Profiler来找到邪恶的根源,但它无法靠近我们自己的任何类。我看到与System.Web.Caching.CacheDependency+DepFileInfo
的连接,因此System.Web.Cache
但我们不使用文件依赖关系来使我们的缓存条目无效。
此外,还有14315个System.Byte[]
实例在堆上占用超过700 MB,让我感到震惊 - 我们使用Byte[]
的唯一地方是我们的图片上传组件,但我们只有大约30个每天上传图片。
这些Byte
数组和FileMonitorTarget
对象的来源可能是什么?任何提示都非常受欢迎!
奥利弗
P.S。有人问了同样的问题here,但唯一的'答案'是非常笼统的。
答案 0 :(得分:1)
我会研究一些事情。你是对的,字符串经常使用很多。你还有约。堆上有1.4 GB的字符串。听起来不错吗?如果不是,我会调查。如果那是预期的范围,请忽略它。
如果您怀疑FileMonitorTarget
和/或Byte[]
泄露,请使用!dumpheap -mt XXX
转储实例,其中XXX是列出的MethodTable
类型。您可能希望使用PSSCOR2而不是SOS,因为它使此任务更容易一些(!dumpheap
的输出显示增量列,您可以限制转储的实例数。)
接下来要做的是开始研究保持特定实例存活的内容。 !gcroot
命令将告诉您特定实例的根。随机选择一个实例并检查根。如果一切都按预期进行到下一个。如果您的应用程序泄漏了这些类型的实例,那么您可能会得到一个应该被释放的实例。一旦获得了根,您需要弄清楚代码的哪一部分正在坚持这些。常见的来源是未订阅的事件,但还有其他可能的原因可以保持对象保持活动状态。
答案 1 :(得分:1)
ASP.NET自动创建System.Web.Caching.CacheDependency + DepFileInfo类型的对象,以监视对您网站的文件更改。因此,即使您没有专门使用FileDependency缓存过期,ASP.NET本身也会这样做。
如果我针对其中一些对象运行转储字段,我会获得控件/页面的路径。
0:000> !df -field _filename 0d3f24ec
Name: System.String
MethodTable: 79330b24
EEClass: 790ed65c
Size: 180(0xb4) bytes
GC Generation: 2
(C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
String: C:\inetpub\wwwroot\Website\Application\Base\UserControl\Messages.ascx
Fields:
MT Field Offset Type VT Attr Value Name
79332d70 4000096 4 System.Int32 1 instance 82 m_arrayLength
79332d70 4000097 8 System.Int32 1 instance 81 m_stringLength
79331804 4000098 c System.Char 1 instance 44 m_firstChar
79330b24 4000099 10 System.String 0 shared static Empty
>> Domain:Value 000e0ba0:02581198 00109f28:02581198 <<
79331754 400009a 14 System.Char[] 0 shared static WhitespaceChars
>> Domain:Value 000e0ba0:025816f0 00109f28:02586410 <<
您可以看到此链接描述更多细节:Understanding ASP.NET Dynamic Compilation
但是,您的情况可能仍然不同。尝试运行!GCRoot [obj_addr]并查看保留这些对象的内容。在我的例子中,它完全是IIS / .NET相关的对象。
那就是说,我仍然遇到了创建数百万个缓存对象的问题,我不明白为什么。 :| (这是第一次发生在我身上,但我认为它不会出现或者会神奇地消失......)