这(必然)是内存泄漏吗?
嗯……是的,不是的。在 C# 应用程序中,大部分情况下不可能发生真正的内存泄漏,如果从未调用过 Dispose(),即使在后台使用本机资源的类型也会在其终结器中自行清理。
无论如何,可能有陈旧的引用和本机资源需要很长时间才能清理(或编写不当的本机函数会泄漏自身),这与非托管语言中真正的内存泄漏具有相同的实际结果。
为什么强制 GC 没有帮助?
你给了 GC 一个建议,它选择不接受。GC.Collect()
不会强制 GC 清理所有内容,文档也会告诉您。其次,这种内存使用真的会导致问题吗?消耗了多少内存?它会被释放吗?如果只是少量,那么您可能什么都不担心,让 GC 完成它的工作。
在没有看到您的代码的情况下,我所能做的就是猜测。有几种方法可以在 C# 应用程序中建立内存压力。
陈旧的参考资料。对您永远不会清除的“死”对象的引用列表。事件处理程序也可能导致这种情况。例如,应始终取消订阅静态事件,因为事件委托持有对订阅者的引用。
因此,如果订阅者在没有取消订阅事件的情况下超出范围,则本质上存在内存泄漏,因为始终存在对这些“死”对象的有效引用。请注意,事件的典型用例不会导致这种情况发生,因为父级(事件发布者)通常会在您需要时超出范围。
不处理实现 IDisposable 的对象。当然,它们可能会在它们的终结器中自行清理(所有 .NET IDisposable 类型都会这样做,其余的应该),但是终结器在不确定的时间运行,这使得整个事情变得不可预测。确保尽快调用 Dispose()(尽可能使用using
语句)。
大对象堆碎片。如果您要分配大量“大”对象(> 85,000 字节的对象),那么这部分内存可能会变得碎片化。此内存不会像在标准堆上分配的第 0 代和第 1 代对象那样经常清理。
.NET GC 很复杂,而且通常非常擅长它的工作。有时调用 是可以接受的GC.Collect
,但您应该了解何时这是一个好主意,并意识到它可能会或可能不会按照您的意愿行事。例如,如果您创建了大量的短期对象。
当我用尽其他途径时,我在使用RedGate 的 .NET 内存分析器时获得了很好的体验。我不为他们工作,也不以任何方式与他们有任何关系,正如你所知,他们也有免费试用。值得一看。