内存泄漏问题

时间:2010-11-03 00:44:18

标签: c# garbage-collection dispose idisposable

我已经阅读了很多关于此问题,因为我被要求修复一个有内存泄漏问题的C#应用​​程序,但我没有找到这两个问题的答案:

请考虑以下代码:

   private static ArrayList list = new ArrayList();

   public void Function()
   {
     list.add(object1);
     list.add(object2);

     //didn't call clear() prior to reusing list
     list = new ArrayList();
   }

由于列表在创建新列表之前未被清除,是否会产生某种垃圾,在静态列表本身被释放后不会被释放?

第二个问题是关于Form.Dispose()。我看到设计师视图(即标签,图片框)上的许多控件都需要处理。似乎在Form上调用Dispose()会导致所有这些类型的控件也被处理掉(如果我错了就纠正我),这很奇怪,因为设计师添加了一个覆盖 void Dispose(bool disposing) 没有这样的东西的方法。我假设这发生在基本Form类的 void Dispose(bool disposing)方法中。

上述问题是我不清楚我需要做些什么才能确保正确处理所有Form的资源。我不明白Form如何知道它需要处理哪些对象。例如,如果在我的表单中我有一个自定义IDisposable对象的字段,表单是否知道它需要处理?或者我应该添加自己发布对象所需的代码吗?

另外,如果我确实需要添加代码来处理某些对象,那么我该如何处理设计者已经覆盖 void Dispose(bool disposing)方法的事实呢?我应该编辑设计器生成的代码还是有更简洁的方法来执行此操作?

我希望这不要混淆,这有点难以解释。感谢

3 个答案:

答案 0 :(得分:8)

不,那不是泄密。当垃圾收集器搜索对象引用时,它将不再找到对原始ArrayList的引用。你替换了它。因此,它会自动销毁原始的ArrayList对象,以及它们在任何地方都没有被引用的所有元素。

Form类知道如何自行处理,以及该窗体上作为子窗口的所有控件。当用户关闭表单时会发生这种情况,Windows发送的WM_CLOSE消息会触发此代码。 Form.Controls集合可帮助它找到对所有子控件的引用,以便它也可以处理它们。

但是,如果您自己从表单中删除控件,则不会发生这种情况。现在你可以在它们上面调用Dispose()了。特别是Controls.Clear()方法很危险。有什么不寻常之处在于它会导致永久性泄漏,你移除的控制装置会被“停车窗口”保持活着。这使窗口句柄保持活动状态,以便您可以将它们移动到其他容器窗口上,例如。如果你实际上没有移动它们,它们将永远保留在停车窗口上。框架中的其他类都没有这种方式。

使用Taskmgr.exe,进程选项卡可以轻松诊断此泄漏。查看+选择列并勾选用户对象。如果程序运行时这种情况稳步上升,那么你就会泄漏控件。

答案 1 :(得分:1)

Static arraylist的范围是什么?在我看来它有一个表单范围。如果是,则不会处理它,因为静态对象始终被认为是有根的并且具有应用程序生命周期。根据我的经验,由于这个事实,静力学总是需要更多的记忆并被提升到第二代。如果您有任何疑问,请使用.net内存分析器并检查它。您还可以使用windbg进行内存转储并对其进行分析,以找出泄漏的真正原因。

答案 2 :(得分:1)

在许多内存管理框架中,垃圾收集和其他方式,释放应用程序内的内存通常不会导致应用程序释放该内存,而是记录内存应该可用于将来的请求。垃圾收集背后的部分想法是,当用户代码要求内存并且应用程序知道它至少具有立即可用的数量时,代码和应用程​​序都不会关心该请求所需的任何内存是否“已分配”或“免费”。当一个对象的最后一个可达参考被破坏或变得无法访问时,该对象就会在当时和那里有效地停止存在,但通常没有太多的目的试图回收以前由不存在的对象使用的内存,直到要求这样的回收为止。满足分配请求,或“每次花费的内存释放”比率与其可能获得的一样好。

请注意,要让系统回收与对象关联的内存,绝对必须不会对该对象存在任何类型的 。如果存在对对象无法访问的任何可到达的弱引用,则垃圾收集器必须使所有此类引用无效(因此它们不再标识该对象),然后才能回收对象使用的空间。如果其他无法访问的对象具有已注册的终结器,则系统必须将该对象放在需要立即完成的事物的队列中(从而使其不符合回收条件)并取消注册终结器。

当放弃对对象的所有其他引用时,弱引用和用于完成的引用都会自动失效,因此不会导致内存泄漏。然而,还有另一种参考,可能导致令人讨厌的泄密:来自发行商的活动订阅超过订阅者。如果对象A订阅了来自对象B的事件,则对象A不能被垃圾收集,除非(1)它取消订阅事件,或者(2)B本身有资格进行垃圾收集。我发现自己很困惑为什么微软没有包含一些自动事件取消订阅的方法,但他们没有。