我想要回忆我的记忆! 我怎样才能真正处置控件?

我有一个我正在制作的应用程序,它创建了大量的窗口控件(按钮和标签等)。 它们都是通过function动态制作的。 我遇到的问题是,当我删除控件并处理它们时,它们不会从内存中删除。

void loadALoadOfStuff() { while(tabControlToClear.Controls.Count > 0) tabControlToClear.Controls[0].Dispose(); //I even put in: GC.Collect(); GC.WaitForPendingFinalizers(); foreach(String pagename in globalList) tabControlToClear.Controls.Add(MakeATab(pagename)); } TabPage MakeATab(string tabText) { TabPage newT = new MakeATab(); newT.Text = tabText; //Fill page with controls with methods like this return newT; } 

现在由于某种原因,这只是没有给我回忆,所以当进程运行5次时,我最终会出现内存不足的情况。 我是对象和控制处置的新手,但是通过庞大的网络仍然没有给我任何指示,所以如果你们有任何想法,我会很高兴听到它。

更新:我一直在观察用户对象的创建和销毁(taskmanager),并注意到我创建了一个标签页,添加了一个单击处理程序,添加了一个面板,添加了两个按钮,包括点击处理程序,工具提示和背景图像(我认为这是哪里问题是)。 该应用程序说它创建了8个新项目,但是当我运行我的处理时,我只从内存中删除4个。 我一直试图删除事件处理程序,但它似乎没有任何区别。

解决!!! 当我向面板添加新项目时,我向他们传递了一个工具提示(愚蠢,但我正在学习)。 对于任何有同样问题的人,(感谢下面的人的评论和指示。我发现,为了使控件真正处置(因为我意识到我错误地把它),是:

1:如果你有工具提示,请确认它是可以访问的! 不要做我想做的事! 例如:

这是错的!

 TabPage MakeATab(string tabText) { TabPage newT = new MakeATab(); ToolTip myTip = new ToolTip(); newT.Text = tabText; //Fill page with controls with methods like this myTip.SetToolTip(newT, "Something to say"); return newT; } 

如果你这样做,你将失去指向工具提示的指针,并且因为工具提示不是它所连接的对象的子节点(相反,工具提示强烈引用控件),那么即使你破坏了控件,您无法访问的工具提示可使对象保持活动状态。

2:在任何事情之前,调用toolTip.RemoveAll()。 这将删除它与控件的所有联系。 请注意,如果您将此提示用于其他控件,则他们只是丢失了他们的工具提示。

3:从基本control.ControlCollection中删除任何内部控件(如果他们使用非托管内存,我猜。我正在这样做因为它使我的应用程序正常工作……)

4:删除任何自定义事件处理程序。

5:最后,配置对象。 我做了一个快速递归function,它做得很好。

  private void RecursiveDispose(Control toDispose) { while (toDispose.Controls.Count > 0) RecursiveDispose(toDispose.Controls[0]); if (toDispose.BackgroundImage != null) BackgroundImage = null; if (toDispose.GetType() == typeof(Button)) toDispose.Click -= [Your Event]; else if (toDispose.GetType() == typeof(TabPage)) toDispose.DoubleClick -= [Your Event]; else if (toDispose.GetType() == typeof(Label)) toDispose.MouseMove -= [Your Event]; toDispose.Dispose(); } 

这是非常粗糙的,并且可能有更好的方法,但除非有人能想出来,否则这将是必须的。 谢谢大家的帮助。 您可能刚刚保存了我的整个项目。

您还需要清除参考。

 while(tabControlToClear.Controls.Count > 0) { var tabPage = tabControlToClear.Controls[0]; tabControlToClear.Controls.RemoveAt(0); tabPage.Dispose(); // Clear out events. foreach (EventHandler subscriber in tabPage.Click.GetInvocationList()) { tabPage.Click -= subscriber; } } 

在此代码块中,您正在调用Dispose但不删除引用:

 while(tabControlToClear.Controls.Count > 0) tabControlToClear.Controls[0].Dispose(); 

您需要删除对控件的所有引用(在Controls集合中加上任何已注册的事件处理程序以及您可能具有的任何其他引用),以使控件有资格进行垃圾回收。

 void loadALoadOfStuff() { while(tabControlToClear.Controls.Count > 0) tabControlToClear.Controls[0].Dispose(); //I even put in: GC.Collect(); GC.WaitForPendingFinalizers(); foreach(String pagename in globalList) tabControlToClear.Controls.Add(MakeATab(pagename)); } 

在我看来,你正在测试方法结束时重新分配所有的选项卡实例,所以显然没有先处理它们的好处。 略过最后两行,看看是否有帮助。

到目前为止,对于这个问题有很多很好的答案,提到一个可能的原因是对象没有被释放,它们都是值得检查的东西。

然而,当我遇到这种类型的问题时,我使用内存分析器来帮助跟踪对象的引用,上次我查看内存分析器时, ANTS Memory Profiler (来自RedGate )是最好的之一。 (他们做了14天的尾巴,足以调查像这样的单一问题。)

这是使用弱事件模式的原因之一,但这将是一个全新的问题 。

(当您动态修改UI时,UI对象的生命周期是一个雷区,为taskmanager做好了检查,确保您的代码按预期工作)