C# 我想要回我的记忆!如何才能真正处置控件?

C# 我想要回我的记忆!如何才能真正处置控件?,c#,memory,controls,dispose,collect,C#,Memory,Controls,Dispose,Collect,我有一个应用程序,我正在创建大量的窗口控件(按钮和标签等)。它们都是通过函数动态生成的。我遇到的问题是,当我删除控件并处理它们时,它们不会从内存中删除 void loadALoadOfStuff() { while(tabControlToClear.Controls.Count > 0) tabControlToClear.Controls[0].Dispose(); //I even put in: GC.Collect(); GC.Wa

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

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个新项目,但当我运行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:从base 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();
    }

这是非常粗糙的,可能有更好的方法,但除非有人能想出它,否则就只能这样做。谢谢大家的帮助。您可能已经保存了我的整个项目。

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

while(tabControlToClear.Controls.Count > 0)
    tabControlToClear.Controls[0].Dispose();
您需要删除对控件的所有引用(在控件集合中,加上任何已注册的事件处理程序,再加上您可能拥有的任何其他引用),控件才有资格进行垃圾收集

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));
}

在我看来,您在测试方法的末尾重新分配了所有选项卡实例,因此首先处理它们显然没有任何好处。跳过最后两行,看看这是否有帮助。

您还需要清除引用

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;
    }
}

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

然而,当我遇到这种类型的问题时,我使用a来帮助跟踪对象的引用,上次我查看内存探查器时,(from)是最好的(他们做了一个14天的跟踪,长度足以调查像这样的单个问题)

这是使用弱事件模式的原因之一,但这将是一个错误


(当您动态修改UI时,UI对象的生存期是一个雷区,taskmanager很好地检查了您的代码是否按预期工作)

我更进一步,我甚至为所有项创建了一个递归dispose方法,但仍然没有内存。private void RecursiveDispose(控件到dispose){while(toDispose.Controls.Count>0)RecursiveDispose(toDispose.Controls[0]);toDispose.Dispose();}同样,这会移除所有可见项并清除控制数组,但我仍然无法收回任何内存。其他原因会导致内存不足错误;一般来说,您不需要调用垃圾收集器。您的实际代码是什么?是的,我刚刚注意到大量用户对象。但我的代码只移除了其中一些。F或者举个例子,当我运行创建时,它生成8个对象,但当我处理这些对象时,它从内存中清除了4个…我应该提到,这不是一个干净的,50%的损失,有时,我生成了11个项目,清除了6个。这很奇怪。至于我的实际代码,放在这里有点大。很好,尽管OP没有提到任何事件子项。忘记了事件处理程序分配是“内存泄漏”的常见原因。混乱,我可能听起来有点晦涩(我是新来的,发发发慈悲吧),但那个代码不起作用。可能是“tabPage.Dispose();”应在分离事件处理程序后调用?感谢提供的信息,我有一些处理程序分配给各种控件,但如何创建递归清除函数?我有嵌套在面板上的按钮和标签,放置在添加到选项卡控件的选项卡页上。嵌套非常严重。我如何处理对象及其处理程序的处置如果不知道控件的类型?另外,我在这些控件上附加了工具提示,是否需要处理它们?此函数的目的是删除所有控件,将其从内存中释放并替换为新控件。通过删除最后两行,我删除了编写此函数的原因,即在处理旧控件后填充页面,不需要的对象。不仅仅是处理。如果你提到你的内存使用量增加,我会建议你这么说。但是,我假设你抱怨内存使用率一直很高。不,我正在动态创建1000多个用户控件…当它们清除时,我需要回内存…正如我发现的,用户控件法力