gpt4 book ai didi

.net - 在 Windows 窗体中添加和删除控件和内存使用

转载 作者:行者123 更新时间:2023-12-05 08:44:46 24 4
gpt4 key购买 nike

我有一个带有面板控件的 WindowsForm,我用它来显示我的用户控件。我以这种方式添加控件:

private void AddControl(Control control)
{
panel.Controls.Clear();
control.Size = new Size(panel.Width - 1, panel.Height - 1);
control.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles. Top;
panel.Controls.Add(control);
}

..

AddControl(new ucSomeControl());

我只是点击了每个使用 AddControl() 的按钮,每次都看到内存使用量增加。我让应用程序继续运行,什么也不做,持续了一个半小时,内存使用量从 140mb 下降到 138mb,就像 2mbs 一样。您认为这是正常的,还是我的控件添加方法有问题,我应该/可以改进以减少内存使用量?

跟进

我已经为我的应用程序创建了 4 个版本:Debug、Release、Dispose、manuel GC 调用。

用我的原始代码

在内存使用方面,我的应用程序的调试版本和发布版本之间几乎没有区别,例如 5mb。这些版本的问题在于,我点击按钮的次数越多,即使我点击同一个按钮并再次创建同一个 UserControl,内存使用量同样会增加。

使用处置

我添加了 Chris Arnold 的 Dispose 代码。内存使用量显着降低,尽管创建越来越多的控件仍然会增加内存使用量,但现在每个控件使用的内存要少得多。这是一个有值(value)的附录。

使用手动 GC 调用

我在 Dispose 之后添加了这段代码:

GC.Collect();
GC.WaitForPendingFinalizers();

宾果游戏!甚至比 Dispose 代码更少的内存使用。最好的部分是,即使我一遍又一遍地创建新控件,内存使用量的增加也非常小,几乎微不足道。

我真的很喜欢使用 Dispose + GC 方法,但我所关注的关于手动 GC 调用的每一篇文章都强烈反对使用它。即使我没有任何自定义终结器/析构器,我也不确定是否使用它..

最佳答案

您可以使用 TaskMgr.exe、“进程”选项卡查看发生了什么。查看+选择列并勾选“用户对象”。此列跟踪窗口句柄。请注意,当您单击该按钮时,此列的值会不断增加。调用 GC.Collect() 不会使它下降。一旦达到 10,000,您的程序就会崩溃并烧毁。

Control 类是我所知道的 .NET 框架中唯一需要调用 Dispose() 的类。终结器不足以确保释放窗口句柄。调用 Dispose() 通常是完全自动的,控件的父级在它被释放时执行。最终父级是 Form 对象,它在关闭时自动处置自身(及其子控件)。

但是当您自己从 Controls 集合中删除控件时,这不会发生。您不能使用 Clear() 方法,您必须这样做:

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

之所以这样工作,是因为窗口的生命周期是由 Windows 管理的,而不是您的程序。只要窗口处于事件状态,控件包装器就不应被垃圾回收。 Windows 窗体在内部表中跟踪窗口句柄。只要 Handle 有效,该表就会确保 Control 类包装器不会被垃圾回收。换句话说,总是至少有一个对 Control 对象的引用。

在窗口收到 WM_NCDESTROY 消息之前,该引用不会从该内部表中删除,这是窗口过程在销毁窗口句柄之前收到的最后一条消息。从 Controls 集合中移除控件不足以破坏窗口。如果您不显式调用 Dispose(),它将变成一个“僵尸”,一个不可见的窗口,您无法获取其控件包装器引用。

关于.net - 在 Windows 窗体中添加和删除控件和内存使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2032896/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com