应该如何处理'如果(处置)'

我一直在修复winforms应用程序中的一些内存泄漏问题,并注意到一些不显式放弃的对象(开发人员没有称为Dispose方法)。 Finalize方法的实现也没有帮助,因为它没有进入if (disposing)子句。 所有的静态事件注销和收集清除都已经放在if (disposing)条款中。 最好的做法是调用Dispose,如果对象是一次性的,但不幸的是,这种情况有时会发生

如果有非托管对象,静态事件处理程序和一些托管集合,这些集合在处置时需要清除。 如何决定应该如何if (disposing)以及if (disposing)条款应该如何if (disposing)

配置方法。

// 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;
     }
 }

它说托管对象应该在if (disposing) ,只有当显式调用由开发者调用的Dispose方法时才正常执行。 如果Finalize方法已经实现并且开发人员忘记调用Dispose方法,那么通过Finalizer进入的执行不会进入if (disposing)部分。

以下是我的问题。

  • 如果我有导致内存泄漏的静态事件处理程序,我应该在哪里取消注册? if (disposing)条款中是否出现?

  • 如果我有一些导致内存泄漏的集合,我应该在哪里清除它们? if (disposing)条款中是否出现?

  • 如果我正在使用第三方的一次性对象(例如:devExpress winform控件),我不确定它们是托管对象还是非托管对象。 假设我想在处理表单时处理它们。 我怎么知道什么是管理的,什么是非管理对象? 一次性使用不是这样说的吗? 在这种情况下,如何确定应该如何if (disposing)以及if (disposing)条款应该如何if (disposing)

  • 如果我不确定是否管理或不管理,那么从if (disposing)条款中处置/清除/注销事件的坏处是什么? 假设它在处置之前检查为空?

  • 编辑

    我的意思是作为事件取消注册是下面的东西。 Publisher是一个长期存在的实例,下面一行是订阅者的构造函数。 在这种情况下,用户需要取消注册该事件并在发布者之前进行处置。

    publisher.DoSomeEvent += subscriber.DoSomething;
    

    这里要记住的关键是IDisposable的目的。 它的工作是在垃圾收集对象之前帮助您确定性地释放代码持有的资源。 其实,这就是为什么C#语言的团队选择了关键字using ,作为支架确定对象和它的资源是由应用程序所需要的范围。

    例如,如果打开到数据库的连接,则需要释放该连接并在完成处理后尽快关闭它,而不是等待下一次垃圾回收。 这是您实施处理器的地点和原因。

    第二种情况是协助非托管代码。 实际上,这与C ++ / C API调用操作系统有关,在这种情况下,您有责任确保代码不会泄露。 尽管许多.Net被写入简单的P / Invoke到现有的Win32 API,但这种情况很常见。 从操作系统封装资源的任何对象(例如Mutex)都将实现一个Disposer,以便您安全且确定地释放其资源。

    但是,这些API也将实现析构函数,以确保如果不正确使用资源,则不会被操作系统泄漏。 当你调用finalizer时,你不知道你引用的其他对象是否已经被垃圾回收,这就是为什么对它们进行函数调用是不安全的(因为它们可能抛出NullReferenceException ),只有非托管引用根据定义不能垃圾收集)将提供给终结者。

    希望有点帮助。


    一般来说, if (disposing)和其外部的非托管资源,托管资源将置于其内部。 处置模式的工作原理如下:

  • if (disposed) {

    如果这个对象已经处理完毕,不要再处理它。

  • if (disposing) {

    如果以编程方式请求处置( true ),则处置此对象拥有的管理资源(IDisposable对象)。

    如果处置是由垃圾收集器引起的( false ),则不要处置管理资源,因为垃圾收集器可能已经处理了所拥有的管理资源,并且在应用程序终止之前将其明确处置。

  • }

    处置非托管资源并释放对它们的所有引用。 步骤1确保只发生一次。

  • disposed = true

    将该物体标记为已处理以防止重复处置。 在步骤2或3重复处理可能会导致NullReferenceException。

  • 问题1
    不要在Dispose方法中处理它们。 如果您处理了该课程的多个实例,会发生什么? 尽管已经处置了静态成员,但每次都会处理静态成员。 我找到的解决方案是处理AppDomain.DomainUnloaded事件并在那里执行静态处置。

    问题2
    这一切都取决于集合的项目是否被管理或不受管理。 可能值得创建托管包装,为您正在使用的任何非托管类实现IDisposable,以确保管理所有对象。

    问题3
    IDisposable是一个托管界面。 如果一个类实现了IDisposable,它是一个托管类。 在if (disposing)内部处理管理对象。 如果它没有实现IDisposable,那么它可以被管理并且不需要处置,或者不被管理,并且应该在处理if (disposing)之外被if (disposing)

    问题4
    如果应用程序意外终止或不使用手动处理,则垃圾收集器将按随机顺序处理所有对象。 子对象可以在其父母被处置之前被处置,导致父母第二次处置该子女。 大多数托管对象可以安全地多次处理,但前提是它们已经正确构建。 如果一个对象被多次处置,你会冒(尽管不太可能)导致gargabe集合失败。


    如果我有导致内存泄漏的静态事件处理程序,我应该在哪里取消注册? (处置)条款中是否出现?

    对于在类级别使用静态事件处理程序的实例,将调用Dispose方法。 所以你不应该取消注册它们。 通常情况下,静态事件处理程序应该在卸载类时或在应用程序执行过程中的某个时刻取消注册,这样您就不再需要此事件处理程序了。

    对于所有管理和未管理的资源,更好地实施IDisposable模式。 请参阅http://msdn.microsoft.com/en-us/library/fs2xkftw%28VS.80%29.aspx并在C#中完成/处理模式

    链接地址: http://www.djcxy.com/p/54461.html

    上一篇: What should go in 'if (disposing)'

    下一篇: C# how to implement Dispose method