【问题标题】:Out of Memory Exception内存不足异常
【发布时间】:2010-10-05 02:06:46
【问题描述】:

我正在使用 C# 和 asp.net 开发一个 Web 应用程序,我收到了内存不足的异常。该应用程序所做的是从数据源读取一堆记录(产品),可能是数百/数千,通过向导中的设置处理这些记录,然后使用处理产品信息更新不同的数据源。虽然有多个 DB 类,但现在所有的逻辑都在一个大类中。唯一的原因是所有信息都与一件事有关,即产品。如果我将我的应用程序分成不同的类,它会帮助记忆吗?我认为不会,因为如果我将业务逻辑分为两个类,那么这两个类在相互发送消息的整个过程中都会保持活动状态,所以我不知道这会有什么帮助。我想我的另一个解决方案是找出占用所有内存的原因。有什么好工具可以推荐吗?

谢谢

【问题讨论】:

    标签: c# asp.net memory-management


    【解决方案1】:

    您是否使用数据读取器来流式传输您的数据? (避免加载太多到内存中)

    我的直觉告诉我这是一个需要解决的微不足道的问题,不要抽取包含 100 万条记录的数据表,一次处理一行或小批量处理表……完成后释放并处置对象跟他们。 (例如:没有static List<Customer> allCustomers = AllCustomers()
    有一个开发规则,确保如果涉及的行数超过 X,则没有人将表读入内存。

    如果您需要一个工具来调试这个,请查看.net memory profilerwindbg with the sos extension 两者都可以让您嗅探您的托管堆。

    另一个注意事项是,如果您关心可维护性并希望减少缺陷数量,请以更符合您的领域的方式正确删除 SuperDuperDoEverything 类和模型信息。 SuperDuperDoEverything 类是一颗等待爆炸的炸弹。

    【讨论】:

      【解决方案2】:

      另请注意,您可能实际上并没有耗尽内存。发生的情况是 .NET 去寻找连续的内存块,如果找不到,它会抛出 OOM - 即使您有足够的总内存来满足请求。

      有人同时引用了 Perfmon 和 WinDBG。您还可以设置 adplus 以在崩溃时捕获内存转储 - 我相信语法是 adplus -crash -iis。获得内存转储后,您可以执行以下操作:

      .symfix C:\symbols
      .reload
      .loadby sos mscorwks
      !dumpheap -stat
      

      这将使您了解您的高内存对象是什么。

      当然,请查看 Tess Fernandez's 优秀的博客,例如 Memory Leaks with XML Serializers 上的这篇文章以及如何解决它们。

      如果您能够在您的开发环境中重现这一点,并且您拥有 VS Team Edition for Developers,则内置内存分析器。只需启动一个新的性能会话,然后运行您的应用程序。它会吐出一个很好的报告,说明周围有什么。

      最后,确保你的对象没有定义析构函数。这不是 C++,它没有任何确定性,除了它保证你的对象将在一轮垃圾收集中存活,因为它必须被放入终结器队列,然后在下一轮清理。

      【讨论】:

        【解决方案3】:

        您可能想尝试的一个非常基本的事情是,重新启动 Visual Studio(假设您正在使用它)并查看是否发生同样的事情,是的,在不等待垃圾收集器的情况下释放对象始终是一个好习惯。

        总结一下,

        • 释放对象
        • 关闭连接

        而且你总是可以试试这个, http://msdn.microsoft.com/en-us/magazine/cc337887.aspx

        【讨论】:

          【解决方案4】:

          我发现了问题。在执行我的循环时,我有一个没有被清除的集合,因此数据只会不断添加到其中。

          【讨论】:

            【解决方案5】:

            从 Perfmon 开始;有许多计数器用于 GC 相关信息。您很可能正在泄漏内存(否则 GC 将删除对象),这意味着您仍在引用不再需要的数据结构。

            【讨论】:

              【解决方案6】:

              无论如何你都应该分成多个类,只是为了一个理智的设计。

              您要关闭数据库连接吗?如果您正在读取文件,是否在完成读取/写入后关闭/释放它们?其他对象也是如此。

              你可以定期循环你的类对象来释放内存。

              【讨论】: