我一直在修复 winforms 应用程序中的一些内存泄漏问题,并注意到一些未明确处理的一次性对象(开发人员尚未调用 Dispose 方法)。 Finalize 方法的实现也没有帮助,因为它没有进入if (disposing)
条款。所有的静态事件注销和集合清除都已放入if (disposing)
条款。如果对象是一次性的,最佳实践是调用 Dispose,但不幸的是有时会发生这种情况
如果存在非托管对象、静态事件处理程序和一些需要在处置时清除的托管集合。如何决定什么应该进去,什么应该出去if (disposing)
clause.
处置方法。 http://msdn.microsoft.com/en-us/library/system.idisposable.aspx
// Dispose(bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// or indirectly by a user's code. Managed and unmanaged resources
// can be disposed.
// If disposing equals false, the method has been called by the
// runtime from inside the finalizer and you should not reference
// other objects. Only unmanaged resources can be disposed.
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
// Free other state (managed objects).
}
// Free your own state (unmanaged objects).
// Set large fields to null.
disposed = true;
}
}
It says http://msdn.microsoft.com/en-us/library/system.idisposable.aspx管理对象应该在if (disposing)
只有当开发者显式调用Dispose方法时才能正常执行。如果 Finalize 方法已经实现并且开发人员忘记调用 Dispose 方法,则通过 Finalizer 到达这里的执行不会进入if (disposing)
部分。
以下是我的问题。
如果我有导致内存泄漏的静态事件处理程序,我应该在哪里取消注册它们?进或出if (disposing)
条款?
如果我有一些导致内存泄漏的集合,我应该在哪里清除它们?进或出if (disposing)
条款?
如果我使用第三方一次性对象(例如:devExpress winform 控件),我不确定它们是托管对象还是非托管对象。假设我想在处理表单时处理它们。我如何知道什么是托管对象,什么是非托管对象?一次性不是这么说的吗?在这种情况下,如何决定什么应该进去,什么应该出去if (disposing)
条款?
如果我不确定某些托管或非托管的事件可能会因处置/清除/取消注册事件而产生不良后果if (disposing)
条款?假设它在处理之前检查是否为空?
Edit
我的意思是事件取消注册如下所示。发布者是一个长期存在的实例,下面一行位于订阅者的构造函数中。在这种情况下,订阅者需要取消注册事件并在发布者之前进行处理。
publisher.DoSomeEvent += subscriber.DoSomething;
广义上讲,托管资源被部署在内部if (disposing)
以及其外部的非托管资源。处置模式的工作原理如下:
-
if (disposed) {
如果该对象已被处置,请不要再次处置它。
-
if (disposing) {
如果以编程方式请求处置(true
),处置该对象拥有的托管资源(IDisposable 对象)。
如果处置是由垃圾收集器造成的(false
),不要处置托管资源,因为垃圾收集器可能已经处置了拥有的托管资源,并且肯定会在应用程序终止之前处置它们。
-
}
处置非托管资源并释放对它们的所有引用。第 1 步确保这只发生一次。
-
disposed = true
将此对象标记为已处置,以防止重复处置。重复处置可能会在步骤 2 或 3 中导致 NullReferenceException。
问题1
不要将它们丢弃在Dispose
根本没有方法。如果您处置该类的多个实例会发生什么?您每次都会处理静态成员,尽管它们已经被处理过。我找到的解决方案是处理AppDomain.DomainUnloaded http://msdn.microsoft.com/en-us/library/system.appdomain.domainunload.aspx事件并在那里执行静态处理。
问题2
这完全取决于集合中的项目是托管的还是非托管的。可能值得创建托管包装器来为您正在使用的任何非托管类实现 IDisposable,以确保所有对象都受到管理。
问题3
IDisposable 是一个托管接口。如果一个类实现了 IDisposable,那么它就是一个托管类。处理里面的托管对象if (disposing)
。如果它没有实现 IDisposable,则它要么是托管的并且不需要处置,要么是非托管的并且应该在外部处置if (disposing)
.
问题4
如果应用程序意外终止,或者不使用手动处置,垃圾收集器将以随机顺序处置所有对象。子对象可能会在其父对象被处置之前被处置,从而导致子对象被父对象第二次处置。大多数托管对象都可以安全地多次处置,但前提是它们已正确构建。如果多次处置某个对象,您可能会面临(尽管不太可能)导致 gargabe 收集失败的风险。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)