我正在制作一个应用程序,创建了大量的窗口控件(按钮、标签等),它们都是通过函数动态创建的。我遇到的问题是,当我移除这些控件并释放它们的内存时,它们并没有从内存中彻底移除。
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次时,我就会遇到内存违规的情况。虽然我对对象和控件释放不太熟悉,但是在广阔的网络上寻找仍未得到任何指示,如果您有任何想法,我将不胜感激。
更新:我一直在观察用户对象的创建和销毁(任务管理器),发现我创建了一个选项卡页,添加了一个单击处理程序,添加了一个面板,添加了两个带有单击处理程序、工具提示和背景图像的按钮(I think this is where the problem is)。应用程序说它创建了8个新项目,但是当我运行我的dispose时,我只从内存中删除了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();
}
这种方法非常粗糙,可能有更好的方式来解决问题,但是除非有人能够想出更好的方法,否则这将是必须采用的。感谢大家的帮助,你们可能刚刚拯救了我的整个项目。
private void RecursiveDispose(Control toDispose) { while (toDispose.Controls.Count > 0) RecursiveDispose(toDispose.Controls[0]); toDispose.Dispose(); }
这样做可以清除所有可见的项目并清空控件数组,但我仍然没有得到任何内存回收。 - user248634