【问题标题】: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 profiler 或windbg 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++,它没有任何确定性,除了它保证你的对象将在一轮垃圾收集中存活,因为它必须被放入终结器队列,然后在下一轮清理。
【解决方案4】:
我发现了问题。在执行我的循环时,我有一个没有被清除的集合,因此数据只会不断添加到其中。
【解决方案5】:
从 Perfmon 开始;有许多计数器用于 GC 相关信息。您很可能正在泄漏内存(否则 GC 将删除对象),这意味着您仍在引用不再需要的数据结构。
【解决方案6】:
无论如何你都应该分成多个类,只是为了一个理智的设计。
您要关闭数据库连接吗?如果您正在读取文件,是否在完成读取/写入后关闭/释放它们?其他对象也是如此。
你可以定期循环你的类对象来释放内存。