Dispose and Finalizer in C#

CLR提供了自动内存管理。Managed memory不需要我们显式地释放。当进行Garbage Collection时,会自动释放。

但是,managed memory仅仅是许多种系统资源中的一种。除了managed memory之外的其他需要显式地释放的资源,被称为unmanaged resources,比如打开的文件描述符,打开的数据库连接等。

CLR提供了释放unmanaged resources的机制。System.Object中声明了一个virtual 方法 Finalize,该方法类似C++中的析构函数,当一个object的内存被回收时,GC会调用Finalize方法释放unmanaged resources。重写了Finalizer的类型也叫做Finalizable类型。

public class ComplexResourceHolder : IDisposable {

    private IntPtr buffer; // unmanaged memory buffer
    private SafeHandle resource; // disposable handle to a resource

    public ComplexResourceHolder(){
        this.buffer = ... // allocates memory
        this.resource = ... // allocates the resource
    }

    ~ ComplexResourceHolder(){
        ReleaseBuffer(buffer); // release unmanaged memory
    }
}

但是使用finalizer有不好的地方

  1. finalizer的调用时间是不确定的。我们不能主动地调用finalizer,只能当GC时由framework调用。这样对于一些稀缺的系统资源,这是不可接受的。
  2. 当GC准备回收一个对象的内存时,如果该对象需要finalize,那么会把该对象放到一个finalize队列中,然后另外一个线程会从该队列中取出对象并调用finalizer。这样,这个对象的内存最快要到下次GC(也有可能第三次、第四次)时才能被回收。因此可能会降低性能。

.Net Framework提供了System.IDisposable接口,通过实现该接口的Dispose方法,我们可以手动调用该方法,这样就可以自己控制unmanaged resources的释放时间。Framework也提供了GC.SuppressFinalize方法告诉GC该对象已经被手动disposed,不需要finalized。这样,该对象的内存就可以被尽快地回收。

.Net推荐的IDisposable接口实现方式如下

    public class ComplexResourceHolder : IDisposable {

        private IntPtr buffer; // unmanaged memory buffer
        private SafeHandle resource; // disposable handle to a resource

        public ComplexResourceHolder(){
            this.buffer = ... // allocates memory
            this.resource = ... // allocates the resource
        }

        // Implement IDisposable.
        // Do not make this method virtual.
        // A derived class should not be able to override this method.
        public void Dispose(){
            Dispose(true);

            // This object will be cleaned up by the Dispose method.
            // Therefore, you should call GC.SupressFinalize to
            // take this object off the finalization queue
            // and prevent finalization code for this object
            // from executing a second time.
            GC.SuppressFinalize(this);
        }

        // Use C# destructor syntax for finalization code.
        // This destructor will run only if the Dispose method
        // does not get called.
        // It gives your base class the opportunity to finalize.
        // Do not provide destructors in types derived from this class.
        ~ComplexResourceHolder(){
            Dispose(false);
        }

        // 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){        

            // release unmanaged memory
            ReleaseBuffer(buffer); 

            // release other disposable objects
            if (disposing){
                if (resource!= null)
                    resource.Dispose();
            }
        }
    }

Reference:

1. http://msdn.microsoft.com/zh-cn/library/system.idisposable.dispose(v=vs.110).aspx

2. http://msdn.microsoft.com/en-us/library/b1yfkh5e(v=vs.110).aspx

时间: 2025-01-12 21:20:53

Dispose and Finalizer in C#的相关文章

C#中Dispose,finalize,GC,析构函数区别(转)

释放类所使用的未托管资源的两种方式:         1.利用运行库强制执行的析构函数,但析构函数的执行是不确定的,而且,由于垃圾收集器的工作方式,它会给运行库增加不可接受的系统开销.         2.IDisposable接口提供了一种机制,允许类的用户控制释放资源的时间,但需要确保执行Dispose(). 一般情况下,最好的方法是执行这两种机制,获得这两种机制的优点,克服其缺点.假定大多数程序员都能正确调用Dispose(),实现IDisposable接口,同时把析构函数作为一种安全的机

C#析构函数(destructor)和终结器(Finalizer) .

使用析构函数释放资源 析构函数用于析构类的实例. 1)         不能在结构中定义析构函数.只能对类使用析构函数. 2)         一个类只能有一个析构函数. 3)         无法继承或重载析构函数. 4)         无法调用析构函数.它们是被自动调用的. 5)         析构函数既没有修饰符,也没有参数. 例如,下面是类 Car 的析构函数的声明: [csharp] view plaincopy class Car { /// <summary> /// 析构函

实现 Dispose 方法

实现 Dispose 方法 MSDN 类型的 Dispose 方法应释放它拥有的所有资源.它还应该通过调用其父类型的 Dispose 方法释放其基类型拥有的所有资源.该父类型的 Dispose 方法应该释放它拥有的所有资源并同样也调用其父类型的 Dispose 方法,从而在整个基类型层次结构中传播此模式.若要确保始终正确地清理资源,Dispose 方法应该可以被多次调用而不引发任何异常. 要点 C++ 程序员不应该使用本主题.而应参见 Destructors and Finalizers in

被www.dispose给坑了

在做AssetBundle资源更新时, 用的是Unity自带的WWW进行下载, 考虑到网络卡的情况下, 做了超时操作. 之前是直接在Update中用Time.time来判断, 假设超过一定时间, www仍未完成,则判断为超时. 其实这样做 虽然也可以说完成了超时判断, 但是TIME_OUT时间设置不好拿捏, 有时候网络真的比较慢的情况下, 下载操作确实比较耗时. 后面无意中发现了www.progress这个属性, 才改成根据progress来判断. 1 public class Download

System.IO.File.Create 不会自动释放,一定要Dispose

这样会导致W3P进程一直占用这个文件 System.IO.File.Create(HttpContext.Current.Server.MapPath(strName)) 最好加上Dispose System.IO.File.Create(HttpContext.Current.Server.MapPath(strName)).Dispose()

强制回收和IDisposable.Dispose方法

如果某对象的 Dispose 方法被调用一次以上,则该对象必须忽略第一次调用后的所有调用. 如果对象的 Dispose 方法被多次调用,该对象一定不要引发异常. 除Dispose 之外的实例方法在资源已释放时会引发 ObjectDisposedException. 用户可能期望资源类型使用特定的约定来表示已分配状态和已释放状态.流类即是这样一种示例,传统上认为它们要么打开要么关闭.具有此种约定的类的实施者可能选择实现具有自定义名称(如“Close”)的公用方法来调用 Dispose 方法. 因为

C# Dispose Finalize

比较值得参考的文档:http://www.jb51.net/article/37214.htm. .NET 的内存管理过程: 托管堆假设内存无限大,线性连续分配内存: 实际内存不够使用时,遍历托管堆对资源,对过期资源进行标记: 移除被标记的资源后对托管堆进行压缩(重新从头开始排列),调整堆指针到空闲内存的开头: 另: 垃圾回收主要且微软推荐让CLR自己进行,不建议用 GC.Collect 指令: 要自己负责非托管资源的回收: Finalize:在 Finalize 内对非托管资源进行回收,以确保

C#中对象的销毁有三种方式Finalize,Dispose,GC。

1.Finalize方法(C#中是析构函数,以下称析构函数)是用于释放非托管资源的,而托管资源会由GC自动回收.所以,我们也可以这样来区分托管和非托管资源.所有会由GC自动回收的资源,就是托管的资源,而不能由GC自动回收的资源,就是非托管资源.在我们的类中直接使用非托管资源的情况很少,所以基本上不用我们写析构函数. 2.大部分的非托管资源会给系统带来很多负面影响,例如数据库连接不被释放就可能导致连接池中的可用数据库连接用尽.文件不关闭会导致其它进程无法读写这个文件等等. 实现模型:1.由于大多数

第七节:使用实现了dispose模式的类型

知道类型如何实现dispose模式之后,接下来看一下开发人员怎样使用提供了dispose模式的类型.这里不再讨论前面的SafeHandle类,而是讨论更常用的FileStream类. 可以利用FileStream打开一个文件,从文件中读取字节,向文件中写入字节,并关闭文件.一个FileStream对象在构造时,它会调用Win32 CreateFile函数,函数返回的句柄保存在SafeFileHandle中,然后通过FileStream对象的一个私有字段来维护运载该对象的引用,FileStream