.Net内存增长问题

3
我有一个应用程序,它会进行大量的文本解析。每次解析后,它都会将一些信息输出到数据库,并清除所有内部状态。
我的问题是,在Windows任务管理器/资源监视器中分配的内存越来越多。我已经使用.Net Mem Profiler做了一些剖析,看起来应该会减少内存。以下是剖析器的截图:
但是,在每次解析之后,任务管理器中的内存私有工作集会增加。我希望内存在使用时增长,然后在每次解析后返回到正常水平,这样我就可以让这个程序一直运行下去。
有什么建议或任何想法导致这种情况吗?

2
你有没有遇到过实际上内存不足的问题?还是这只是预防性的担忧? :) .net 喜欢暂时保留内存...我在这里没有看到什么异常。除非它真的引起了问题,否则我不会太担心它。 - cHao
我有一些大型导入作业,它们在聚合并放入SQL之前使用了几个GB的内存。在执行几个这样的作业后,它会消耗系统上的所有内存并停止工作。 - Luke Belbina
你能发布跟踪结果展示每个代中堆利用率和堆中实例吗?如果在测试中使用小样本数据并在每次运行后比较内存快照,那将更容易进行测试。 - Devendra D. Chavan
请检查以下内容是否有所帮助:.NET中的内存泄漏 - Devendra D. Chavan
如何减少.NET应用程序的内存使用? - Devendra D. Chavan
5个回答

4
一些需要检查的事项:
  1. 事件处理程序会使对象保持活动状态,确保如果订阅事件的对象在发布事件的对象之前从作用域中退出,则取消订阅事件,以防止发布对象保持对它的引用。
  2. 确保对任何实现IDisposable的对象调用dispose。 一般来说,实现IDisposable的对象包含需要进行特殊清理的资源。
  3. 如果引用任何com对象,请确保正确释放它们。
在生产代码中不应调用GC.Collect()

3

任务管理器并不能准确地表示您的应用程序实际使用的内存。它更多地是表示Windows为您的应用程序分配或计划的内存量 - 如果您的应用程序需要更多内存,Windows可以扩展此数字,但如果您的应用程序需要更少内存,则Windows可能不会重新分配此内存,直到另一个应用程序实际需要它。

我认为您上面所说的是您的应用程序实际正在执行的操作的相当准确的表示(即,它没有泄漏)。


有没有一种方法,可以通过 .Net 或编译标志告诉 Windows 释放应用程序的内存。当它在运行时,我不介意它使用几个 GB 的内存,因为实际上是需要的。但是一旦作业处理完成,从 Windows 中获取该内存会很好。 - Luke Belbina

1
这会强制.NET从内存中收集所有未使用的对象,从而重新获取一些内存。
GC.Collect();
GC.WaitForPendingFinalizers();

2
但它不一定会将内存释放给操作系统,因此私有字节可能不受影响。请记住,CLR充当托管应用程序的内存管理器。 - Brian Rasmussen

1

如果您有内存泄漏问题,可以使用SOS调试扩展来尝试找到它。 这篇文章是一个非常好的例子,比我的答案更完整。

您可以在VS或WinDbg中使用它,唯一的区别是如何加载dll。对于Visual Studio,请在项目属性的调试选项卡中启用非托管调试。当加载时,请在立即窗口中使用.load SOS.dll。对于WinDbg,要么打开可执行文件,要么附加到进程,并使用.loadby sos clr(.NET 4)或.loadby sos mscorwks(2或3.5)进行加载。

让应用程序运行一段时间后,暂停它(中断所有操作)。现在您可以加载SOS。成功后,输入!dumpheap -stat。这将列出每个类正在使用多少内存。如果这还不足以找到泄漏,我链接的另一篇文章会更深入地介绍如何定位内存泄漏。


实际上,我猜我读错了图表,所以你可能没有一个(除非我再次读错了 D:)。我想我可以把它留在这里,以防其他人有记忆问题时有用。 - Timiz0r

0

解决这个问题的一种方法是将工作分解成单独的可执行程序。一旦程序完成工作并结束,系统将回收其所有内存。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接