繁体   English   中英

为什么Visual Studio的Windows窗体设计器代码不会导致内存泄漏?

[英]Why doesn't Visual Studio's Windows Form Designer's code cause memory leaks?

据我了解,C#中内存泄漏的主要原因之一是在放置容器时无法取消注册事件侦听器。 因此,每当我手动注册事件时 - 例如Timer.Elapsed += ... - 我确保Timer.Elapsed -= ...当我完成对象(或父对象)时。

但是,我只是查看一个Windows窗体设计器生成的类,并注意到它虽然很乐意订阅事件(例如this.button1.Click += new System.EventHandler(this.button1_Click); ),但似乎没有清理除默认components.Dispose();之外的过程components.Dispose(); 行动。

这是否意味着每个组件的Dispose()方法应该取消注册/取消订阅已绑定到它的任何事件; 如果是这样,组件如何从它不知道的“外部”事件处理程序中注销,这是否意味着手动尝试从标准[IDisposable] Windows控件(计时器,按钮,表单等)中删除事件侦听器不必要?

谢谢

如果包含事件的对象比包含处理程序的对象长,则事件处理程序仅导致内存泄漏。

在典型的WinForms场景中,只要表单打开,控件和表单代码都会存在,所以首先没有问题。

您只需要从静态事件,单例或其他长寿命对象中取消注册处理程序。

好的设计,主要是。 对象模型经过精心设计,以确保事件源不会超过订阅者。 当然有一个循环引用,表单通过其Controls集合以及可能的私有变量保持对控件的引用,控件通过事件订阅添加对表单的引用。 但是控件的生命周期由表单控制,当用户关闭窗口时,两者都会失效。 这将删除对表单对象的通常的唯一引用,保存在将句柄映射到表单的内部表中。 GC对循环引用没有任何问题。

有一些尖锐的边缘,Application.Idle和SystemEvents事件都很麻烦。 他们在MSDN Library中有大量的黄色磁带。

处置也是自动的,不用于取消订阅Winforms中的事件,每个控件都将引用放在自己的Controls集合中。 这从Form类开始,并自动遍历树。 覆盖窗体的Dispose()方法是不常见的,也会引起很多焦虑,因为该方法存在于窗体的Designer.cs文件中。 移动该方法很好,就像使用FormClosed事件作为替代方法一样。

尽管如此,它与电锯的字节有着明显的优势。 在Winforms中,处置控件不是可选的。 非常不寻常,它在框架中的其他任何位置都是可选的,终结器备份忘记调用它。 不在Winforms中,如果使用Controls.Clear或Remove,则不会释放您删除的控件。 它被重新托管到一个名为“停车窗口”的隐藏窗口。 保持控件处于活动状态,将其移动到另一个父级。 不错的功能,除非您不将其移动到其他地方。 它将永远存在于隐藏的窗口,非常讨厌的泄漏。 设计不好。

有一些模式可以解决事件的生命周期问题。 “弱事件模式”在.NET编程中是相当的样板。 它是一个设计问题的蝙蝠信号标志,通常是由喜欢观察者模式引起的,因为它在.NET中工作得很好但不喜欢它附带的合同。 一个霸道的对象模型几乎总是问题的根源,比如[winforms]标签中不应提及名字的三字母缩写词:)

事件源将使订户保持不变。 当表格消失时,它将符合GC的条件,这将使听众符合条件。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM