为什么Visual Studio的Windows Form Designer的代码不会导致内存泄漏

本文关键字:内存 泄漏 Designer Studio Visual Windows Form 为什么 代码 | 更新日期: 2023-09-27 18:37:26

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

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

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

谢谢

为什么Visual Studio的Windows Form Designer的代码不会导致内存泄漏

仅当包含事件的对象比包含处理程序的对象生存期更长时,事件处理程序才会导致内存泄漏。

在典型的 WinForms 方案中,控件和窗体代码仅在窗体打开时存在,因此首先没有问题。

只需从静态事件、单一实例或其他长期对象中注销处理程序。

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

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

处置也是自动的,不用于取消订阅 Winforms 中的事件,每个控件都释放其自己的控件集合中的引用。 它从 Form 类开始,并自动循环访问树。 重写窗体的 Dispose() 方法是不寻常的,也往往会引起很多焦虑,因为该方法存在于窗体的 Designer.cs 文件中。 移动该方法很好,使用 FormClosed 事件作为替代方法进行释放也是如此。

不过,它有一个锋利的边缘,带有电锯的字节。 释放控件在 Winforms 中不是可选的。 非常不寻常,它在框架中的其他任何地方都是可选的,终结器备份忘记调用它。 不在 Winforms 中,如果使用 Controls.Clear 或 Remove 则不会释放您删除的控件。 它被重新托管到称为"停车窗"的隐藏窗口。 使控件保持活动状态以将其移动到另一个父控件。 不错的功能,除非你不把它移到其他地方。 它将永远活在那个隐藏的窗户上,非常讨厌的泄漏。 不好的设计。

有一些模式可以解决事件的生存期问题。 "弱事件模式"在当今的 .NET 编程中是相当样板的。 它是设计问题的蝙蝠信号标志,通常是由于喜欢观察者模式而引起的,因为它在 .NET 中运行良好,但不喜欢随之而来的协定。 霸道的对象模型几乎总是问题的根源,就像三个字母的首字母缩略词一样,其名称不应在 [winforms] 标签中提及:)

事件源将使订阅者保持存在,而不是其他方式。 当表格消失时,它将有资格获得GC,这反过来将使听众有资格。