我正在制作一个创建大量窗口控件(按钮和标签等)的应用程序。它们都是通过函数动态生成的。我遇到的问题是,当我删除控件并处理它们时,它们并没有从内存中删除。
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 次时,我最终会出现内存不足的情况。我是对象和控制处置的新手,但是通过庞大的网络查看仍然没有给我任何迹象,所以如果你们中的任何人有想法,我会很感激听到它。
更新:我一直在观察用户对象的创建和销毁(任务管理器),并注意到我创建了一个标签页,添加了一个点击处理程序,添加了一个面板,添加了 2 个带有点击处理程序、工具提示和背景图像的按钮(我认为这是问题是)。该应用程序说它创建了 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:最后,处理对象。我做了一个快速递归函数,它做得很好。
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();
}
这是非常粗糙的,可能有更好的方法来做,但除非有人能想出它,否则必须这样做。谢谢大家的帮助。您可能刚刚保存了我的整个项目。