【问题标题】:OutOfMemoryException - out of ideasOutOfMemoryException - 没有想法
【发布时间】:2010-03-24 12:15:50
【问题描述】:

我知道我的问题没有简单的答案,但我希望能提供想法、指南或 一些值得一看的东西

我有一个不断抛出 OutOfMemoryException 的网络 Windows 服务。 该服务有两个针对 x86 和 x64 Windows 的构建。但是在 x64 上它消耗更多 记忆。我尝试使用各种内存分析器对其进行分析。但我不知道问题是什么。诊断 - 服务会在 3 到 12 小时后消耗大量 VMSize 并导致应用程序崩溃。行为相当随机 - 没有可观察到的崩溃场景模式。

我还尝试查看性能计数器 (perfmon.exe)。我能看到的是 堆大小正在增长,%GC 时间平均为 19%。此外,内存分配与 %CPU 时间相关。

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

仅仅是GC不够快吗 到 GC 对象或一些非托管 (windows) 对象正在消耗 内存?

查看列表中的第一个应用 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

【问题讨论】:

  • 在我看来你有一些没有释放的对象(内存泄漏),或者你的 CPU 工作太多以至于框架决定不运行垃圾收集器。另请查看 MSDN 上垃圾收集器的延迟模式 - msdn.microsoft.com/en-us/library/bb384202.aspx。到目前为止,您使用过哪个内存分析器?
  • 你是否从数据库中查询了大量数据?
  • 在使用像memprofiler.com 这样的内存分析器时,您无需等待内存不足错误,您可以在泄漏失控之前看到泄漏。在这些情况下,分析器不应崩溃。
  • @Captain Comic:如果要排除由于处理器忙而导致GC没有运行,请在关键位置或计时器中放入GC.Collect()强制收集。如果内存仍然增加,则说明您有未释放的对象。
  • 发生未处理的异常 OutOfIdeasException...

标签: c# .net profiling out-of-memory


【解决方案1】:

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

Tess Ferrandez 有很多出色的演示。 She goes through the most useful stuff here...

【讨论】:

    【解决方案2】:

    您的问题可能是典型的泄漏(对象在不应该植根时仍然植根)或大型对象堆 (LOH) 碎片。

    我发现诊断此类问题的最佳工具是 Windows 调试器的 Son of Strike (SOS) 扩展。下载 Microsoft 的 Debugging Tools for 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. 事件订阅为订阅对象提供了一个额外的根,这很容易忘记.)

    【讨论】:

    • 嗨,Paul,CDB 或 WinDbg 可以附加到正在运行的进程吗?
    • 是的,运行“CDB -pv -p 1234”,其中 1234 是进程 ID。
    • (另外,'q' 会退出调试器并解冻您的进程。)
    【解决方案3】:

    我使用过.Net Memory Profiler,它比微软的 clr profiler 好得多。你必须稍微了解一下。它可以告诉您哪个对象没有被处理或有引用。您还可以根据类型和内存对对象进行排序。我使用了试用版,试用版持续了 30 天,在此期间我能够解决我的应用程序中的问题。

    【讨论】:

      【解决方案4】:

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

      我写过关于identifying high CPU in GC because of LOH 的博客,其中展示了如何获取在 LOH 中分配的确切调用堆栈。

      希望这会有所帮助。

      【讨论】:

        猜你喜欢
        • 2011-01-31
        • 2011-07-05
        • 1970-01-01
        • 2014-06-06
        • 2013-01-28
        • 2011-01-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多