Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/314.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么';t Visual Studio';s Windows窗体设计器';s代码导致内存泄漏?_C#_Memory Management_Idisposable - Fatal编程技术网

C# 为什么';t Visual Studio';s Windows窗体设计器';s代码导致内存泄漏?

C# 为什么';t Visual Studio';s Windows窗体设计器';s代码导致内存泄漏?,c#,memory-management,idisposable,C#,Memory Management,Idisposable,据我所知,C#中内存泄漏的主要原因之一是在释放容器时未能注销事件侦听器。由于这个原因,每当我手动注册一个事件(例如Timer.appead+=…)时,当我完成对象(或父对象)时,我都会确保Timer.appead-=… 然而,我只是查看了一个Windows窗体设计器生成的类,并注意到尽管它很乐意订阅事件(例如,this.button1.Click+=new System.EventHandler(this.button1_Click);),但似乎除了默认的组件.Dispose()之外,没有任何清

据我所知,C#中内存泄漏的主要原因之一是在释放容器时未能注销事件侦听器。由于这个原因,每当我手动注册一个事件(例如
Timer.appead+=…
)时,当我完成对象(或父对象)时,我都会确保
Timer.appead-=…

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

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


谢谢

只有当包含事件的对象比包含处理程序的对象寿命长时,事件处理程序才会导致内存泄漏

在典型的WinForms场景中,控件和表单代码只有在表单打开时才有效,因此首先没有问题


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

事件源将保持订阅者的状态,而不是相反。当表单消失时,它将符合GC的条件,这将使侦听器符合条件

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

有一些尖锐的边缘,应用程序。空闲和系统事件是麻烦。MSDN库中有大量黄色磁带

处理也是自动的,不用于取消订阅Winforms中的事件,每个控件在其自己的控件集合中处理引用。它从Form类开始,自动遍历树。重写表单的Dispose()方法是不寻常的,而且由于该方法存在于表单的Designer.cs文件中,因此往往会引起很多担忧。移动该方法是可以的,使用FormClosed事件作为替代方法进行处理也是可以的

但是它有一个锋利的边缘,就像链锯一样。在Winforms中,释放控件不是可选的。非常不寻常的是,它在框架中的其他地方都是可选的,终结器备份时忘记调用它。不在Winforms中,如果您使用控件。清除或删除,则不会释放您删除的控件。它被重新定位到一个被称为“停车窗口”的隐藏窗口。使控件保持活动状态以将其移动到另一个父级。很好的功能,除非你不把它移到别处。它将永远活在那个隐藏的窗户上,非常严重的泄漏。设计不好


有一些模式可以解决事件的生存期问题。“弱事件模式”在今天的.NET编程中是相当典型的。这是一个设计问题的bat信号,通常是因为喜欢观察者模式,因为它在.NET中运行得很好,但不喜欢它附带的契约。傲慢的对象模型几乎总是问题的根源,就像[winforms]标签中不应提及其名称的三个字母缩写:)

谢谢,这是一个很好的解释。为了确保我正确理解了您的意思,在创建对象的同一类/对象中注册和处理的任何事件都不需要显式删除(除非出于任何原因特别需要),这是真的吗?i、 e.如果
Class1
包含
Object1
,并且
Object1.OnStart()
的事件被注册、处理并完全包含在
Class1
中,当
Class1
被释放时,无需取消注册
OnStart()
,因为它将与
Class1
同时“删除”;但是,如果订阅了
Class2
,则需要执行此清理吗?@Alfie:是的,除非
Object1
在其他地方被引用,并且寿命更长。我知道这是一个有点琐碎的问题,但我在这方面研究过的资源的作者似乎没有意识到这一点,我更愿意了解发生了什么,而不是盲目地遵循“以防万一”的方法。+1对于简洁的答案,它有所帮助,但对于细节,要归功于@SLaks。再次为你的深刻理解而欢呼。虽然上面已经回答了我的问题,但我仍然非常感谢您提供的信息。虽然,现在我必须花一个小时,我没有预料到会学到更多:)嗯,知识永远不应该是可怕的。欣赏SLaks的帖子当然更舒服,这是一个简单的帖子。我很高兴向有鉴赏力的读者介绍这些细节。我所做的。只要把它放在你的脑海里,总有一天你会遇到它,只需要几个小时而不是一个星期就能找到问题:)知识不会吓到我,而是在浏览MSDN等时偶然发现此类信息的不可能的现实。让我害怕的是我不知道的东西,讽刺的是,我学到的越多,我意识到我知道的越少:)你不是该写一本书了吗Tha