在这里遇到我们的网络应用程序的棘手问题。 (Asp.net 2.0 Win server 2008)
我们对网站的内存使用量增长和增长,即使我希望它保持在相当静态的水平。 (我们有少量数据存储在状态中。)
想要找出问题所在,我运行了一个System.GC.Collect();几次,采取内存转储,然后将此内存转储加载到WinDbg。
当我执行DumpHeap -Stat时,我会在特定类型中获得一个非常大的数字,这些数字会在内存中徘徊。
0000064280580b40 713471 79908752 PaymentOption
所以,为这种类型做一个DumpHeap -MT,我得到一堆对象引用。挑选一些随机数,我做了一个!gcroot,命令回来报告没有引用它。
对我来说,这正是GC应该收集这些项目的时候,但由于某种原因,它们一直处于劣势。
任何人都可以解释可能发生的事情吗?
答案 0 :(得分:4)
您可以尝试在Windbg中使用sosex.dll,这是为帮助.NET调试而编写的扩展。有一个名为!refs的命令,类似于!gcroot,因为它会显示所有引用对象的对象,并且它将显示它也引用的所有对象。
在作者网站上的示例中,!refs用于对象,输出如下:
0:000> !refs 0000000080000db8
Objects referenced by 0000000080000db8 (System.Threading.Mutex):
0000000080000ef0 32 Microsoft.Win32.SafeHandles.SafeWaitHandle
Objects referencing 0000000080000db8 (System.Threading.Mutex):
0000000080000e08 72 System.Threading.Mutex+<>c__DisplayClass3
0000000080000e50 64 System.Runtime.CompilerServices.RuntimeHelpers+CleanupCode
答案 1 :(得分:2)
少数事情:
答案 2 :(得分:2)
PaymentObject是否有机会实现终结器?它是否调用STA COM对象?
我很想看到!finalizequeue的输出,看看堆上显示的对象的数量是否等于可能等待最终确定的数量。输出应该看起来像这样:
generation 0 has 57 finalizable objects (0409b5cc->0409b6b0)
generation 1 has 55 finalizable objects (0409b4f0->0409b5cc)
generation 2 has 0 finalizable objects (0409b4f0->0409b4f0)
Ready for finalization 0 objects (0409b6b0->0409b6b0)
如果准备完成对象的数量继续增长,并且您的某些垃圾收集正在发生(通过perfmon计数器确认),那么它可能是一个阻塞的终结器线程。您可能需要在流程的生命周期内(在回收之前)拍摄多个快照以进行确认。我通常依靠三个幻数,只要该网站受到某种负载。
终结器中的错误可能会阻止终结器线程并阻止对象被收集。
如果PaymentOption对象调用旧的STA COM对象,那么本文ASP.NET Hang and OutOfMemory exceptions caused by STA components可能指向正确的方向。
答案 3 :(得分:1)
并非没有关于您的应用程序的更多信息。但是很久以前我们遇到了一些讨厌的记忆问题。你使用ASP.NET缓存吗?正如雷蒙德·陈(Raymond Chen)所说,“糟糕的缓存策略无法从内存泄漏中获益。”
查看另一个工具 - CLRProfiler.exe - 它将帮助您遍历对象引用树以查看对象的根目录。这也很好:link text
你以前听过这个 - 如果你要GC.Collect,那就错了。
答案 4 :(得分:1)
是否在异步进程中创建了PaymentOption对象?我记得有些事情,如果你不打电话给EndInvoke,你可能会遇到这样的问题。
答案 5 :(得分:1)
我自己一直在调查同一个问题,并且问为什么没有收集过没有引用的对象。
大于85,000字节的对象存储在大对象堆中,从中可以较少地释放内存。
http://msdn.microsoft.com/en-us/magazine/cc534993.aspx
单个PaymentOption可能不是那么大,但它们是否包含在集合中,还是基于类似DataSet的东西?您应该选择PaymentOption / collection / DataSet的几个实例,然后使用sos!objsize命令来查看它们的大小。
不幸的是,这并没有真正回答这个问题。我想我可以信任.net框架来处理需要时释放未使用的内存。但是我看到运行我正在查看的应用程序的工作进程使用了大量内存,即使服务器上的内存看起来很紧张。
答案 6 :(得分:0)
仅供参考,.NET 4中的SOS支持一些可能有帮助的新命令,即!gcwhere
(定位异议的生成; sosex的gcgen)和!findroots
(执行它所说的内容)锡; sosex's!refs)