C#垃圾回收Finalize 和Dispose的理解

C# 中的析构函数其实是重写了 System.Object 中的虚方法 Finalize

三种最常的方法以下: 数据库

  1. 析构函数;(由GC调用,不肯定何时会调用) 函数

  2. 继承IDisposable接口,实现Dispose方法;(能够手动调用。好比数据库的链接,SqlConnection.Dispose(),由于若是及时释放会影响数据库性能。这时候会用到这个,再如:文件的打开,若是不释放会影响其它操做,如删除操做。调用Dispose后这个对象就不能再用了,就等着被GC回收。) 性能

  3. 提供Close方法。(相似Dispose可是,当调用完Close方法后,能够经过Open从新打开) this

  析构函数不能显示调用,而对于后两种方法来讲,都须要进行显示调用才能被执行。而Close与Dispose这两种方法的区别在于,调用完了对象的Close方法后,此对象有可能被从新进行使用;而Dispose方法来讲,此对象所占有的资源须要被标记为无用了,也就是此对象要被销毁,不能再被使用。例如常见.Net类库中的SqlConnection这个类,当调用完Close方法后,能够经过Open从新打开一个数据库链接,当完全不用这个对象了就能够调用Dispose方法来标记此对象无用,等待GC回收。明白了这两种方法的意思后,你们在往本身的类中添加的接口时候,不要歪曲了这二者意思。 spa

析构函数 对象

Dispose方法 继承

Close方法 接口

意义 队列

销毁对象 资源

销毁对象

关闭对象资源

调用方式

不能被显示调用,在GC回收是被调用

须要显示调用

或者经过using语句

须要显示调用

调用时机

不肯定

肯定,在显示调用或者离开using程序块

肯定,在显示调用时

  下面提供一个模式来结合上面的 析构函数和Dispose方法。

  public class BaseResource: IDisposable

  {

  //前面咱们说了析构函数其实是重写了 System.Object 中的虚方法 Finalize, 默认状况下,一个类是没有析构函数的,也就是说,对象被垃圾回收时不会被调用Finalize方法

  ~BaseResource()

  {

  // 为了保持代码的可读性性和可维护性,千万不要在这里写释放非托管资源的代码

  // 必须以Dispose(false)方式调用,以false告诉Dispose(bool disposing)函数是从垃圾回收器在调用Finalize时调用的

  Dispose(false);

  }

  // 没法被客户直接调用

  // 若是 disposing 是 true, 那么这个方法是被客户直接调用的,那么托管的,和非托管的资源均可以释放

  // 若是 disposing 是 false, 那么函数是从垃圾回收器在调用Finalize时调用的,此时不该当引用其余托管对象因此,只能释放非托管资源

  protected virtual void Dispose(bool disposing)

  {

  // 那么这个方法是被客户直接调用的,那么托管的,和非托管的资源均可以释放

  if(disposing)

  {

  // 释放 托管资源

  OtherManagedObject.Dispose();

  }

  //释放非托管资源

  DoUnManagedObjectDispose();

  // 那么这个方法是被客户直接调用的,告诉垃圾回收器从Finalization队列中清除本身,从而阻止垃圾回收器调用Finalize方法.

  if(disposing)

  GC.SuppressFinalize(this);

  }

  //能够被客户直接调用

  public void Dispose()

  {

  //必须以Dispose(true)方式调用,以true告诉Dispose(bool disposing)函数是被客户直接调用的

  Dispose(true);

  }

  }

  上面的范例达到的目的:

  1/ 若是客户没有调用Dispose(),未能及时释放托管和非托管资源,那么在垃圾回收时,还有机会执行Finalize(),释放非托管资源,可是形成了非托管资源的未及时释放的空闲浪费

  2/ 若是客户调用了Dispose(),就能及时释放了托管和非托管资源,那么该对象被垃圾回收时,不回执行Finalize(),提升了非托管资源的使用效率并提高了系统性能

  最后:

  若是您的类中使用了非托管资源,则要考虑提供Close方法,和Open方法。并在您的Dispose方法中先调用 Close方法。

  在使用已经 有类时,如SqlConnection。若是暂时不用这个链接,能够考虑用Close()方法。若是不用了就考虑调用

  Dispose()方法。

相关文章
相关标签/搜索