OutOfMemoryException – 出于想法

我知道我的问题没有简单的答案,但我会欣赏想法,指南或某些东西 – 看看清单

我有一个不断抛出OutOfMemoryException的网络Windows服务。 该服务有两个用于x86和x64 Windows的版本。 但是在x64上它消耗了更多的内存。 我尝试使用各种内存分析器对其进行分析。 但我无法弄清楚问题是什么。 诊断 – 服务消耗了大量的VMSize并在3到12小时后崩溃应用程序。 行为是相当随机的 – 崩溃情景没有可观察的模式。

我还试着看一下性能计数器(perfmon.exe)。 我可以看到堆大小正在增长,%GC时间平均为19%。 内存分配与%CPU时间相关。

我的应用程序有线程和锁定对象,数据库连接和WCF接口。 我想解决的一般问题:

GC GC对象或某些非托管(窗口)对象消耗内存的速度是否足够快?

请参阅列表中的第一个应用程序http://s45.radikal.ru/i109/1003/af/92a389d189e8.jpg http://s45.radikal.ru/i109/1003/af/92a389d189e8.jpg

带有性能计数器的图片链接查看http://s006.radikal.ru/i215/1003/0b/ddb3d6c80809.jpg

您的问题是您不知道消耗大量内存的是什么? 当进程使用大量内存时,您可以打开任务管理器,右键单击您的进程并创建一个转储文件,您可以在windbg中检查该文件以确切了解分配内存的内容。

Tess Ferrandez有很多优秀的演示。 她在这里经历了最有用的东西……

您的问题可能是经典泄漏(当它们不应该存在时仍然生根的对象)或大对象堆(LOH)碎片。

我发现用于诊断此类问题的最佳工具是Windows调试器的Son of Strike(SOS)扩展。 下载Microsoft的Windows调试工具以获取调试器:CDB是控制台调试器(我更喜欢它,因为它似乎更具响应性),WinDbg与MDI应用程序包装相同。 这些工具水平较低,并且有一些学习曲线,但提供了解决问题所需的一切知识。

特别是,运行!DumpHeap -stat来查看哪些类型的对象占用了你的记忆。 如果注意到任何重大碎片,此命令也会在列表底部报告。 !EEHeap将列出堆段 – 如果有很多LOH段,那么我会怀疑LOH碎片。

  0:000> .loadby sos mscorwks
 0:000>!EEHeap -gc
 GC堆数:1
第0代从0x00f7a9b0开始
第1代从0x00e79c3c开始
第2代从0x00b21000开始
短暂的分段上下文:无
 段开始分配大小
 00b20000 00b21000 010029bc 0x004e19bc(5118396)
大对象堆从0x01b21000开始
 段开始分配大小
 01b20000 01b21000 01b8ade0 0x00069de0(433632) 

如果有很多LOH段,那么我会开始怀疑LOH碎片。

不过,在此之前,我有兴趣知道:

  1. 应用程序是否使用string.Intern()?
  2. 应用程序是否具有订阅具有长期对象的事件的临时对象?

(我之所以这样说是因为1. .NET字符串实习表的实现方式可能会导致LOH碎片化; 2.事件订阅为订阅对象提供了一个容易忘记的额外根目录。)

我使用.Net Memory Profiler比使用microsoft的clr profiler好得多。 你必须要了解一点。 它可以告诉您哪个对象没有处理或有引用。 您还可以根据类型和内存对对象进行排序。 我使用了最近30天的试用版,在此期间我能够解决我的申请中的问题。

如果您在GC上花费的百分比时间很长,那么我会看看LOH Allocations perfmon counter。 如果在LOH中频繁分配,这将导致GC努力收集,这是GC花费高百分比时间的原因。

我做了博客关于在GC中识别高CPU的博客,因为它显示了如何获得在LOH中分配的确切调用堆栈。

希望这可以帮助。