析构函数与终结操做

建立对象的时候会调用构造函数初始化实例信息,固然析构函数就是释放对象时作的一些释放操做。数据库

为何须要析构函数,广泛来讲,由于咱们的对象中可能用到了一些非托管的代码,譬如数据库操做,网络,本地文件等等,这些资源网络

不是托管的,因此须要咱们的托管对象在销毁时同事释放那些以前使用到的非托管对象,不然一直未关闭,释放,就可能致使泄漏。函数

若是你的对象中根本没用到这些非托管资源,那么请不要定义析构函数,毕竟有代价的。this

 

一、析构函数被编译后,实际变成了Finalize()方法,因此实际上C#中也不容许你本身定义一个Finalize方法spa

二、.NET中的托管对象回收,都是经过垃圾回收机制来实现的,不用咱们手动就释放。当CLR建立对象的时候,若是发现你定义了析构函数,也就是(Finalize方法),线程

那么建立好对象的时候,会将对象地址另外放到一个“终结队列”上;运行一点时间后,对象在根中没法找到引用,且垃圾回收准备释放该对象的时候,发现其在终结队列有引用,code

则将其引用移动到“终结可达队列”,也就是说通常若是是没有析构方法的对象,此时就被回收了,可是有析构函数的对象,则不会被回收,只是将引用移动到“终结可达队列“。对象

而后程序将继续运行,固然CLR发现”终结可达队列“有几个对象的引用存在,则启动一个单独的线程,来遍历队列中的对象,执行其析构函数,并将引用从”终结可达队列“清除。blog

Ok,这时譬如运行一点时间后,垃圾回收操做又开始清理了,这时候在回收其它垃圾对象的同时,会把以前”终结可达队列“上的那些对象一并清除。队列

也就是说有析构函数的对象,实际上要执行两次的垃圾回收操做,才能释放内存。全部有析构函数的对象时有代价的,可是又是必须的,毕竟确实须要释放一些非托管的资源。

 

三、经过上面的那些过程了解到,析构函数无非是为了当对象销毁以前去作一些非托管资源的释放,但却所以提升了释放的代价,

那么假如咱们知道某个对象不须要非托管资源了,那么其实就能够手动去释放,不比等到垃圾回收的时候去释放。所以.NET提供了一个Dispose形式,调用Dispose来手动释放非托管资源。可是嘛,析构函数仍是会照样保存,以避免有些状况忘记了去释放,毕竟析构函数是是CLR调用的。也许你会想,那么就算手动调用Dispose释放了非托管资源,那么

对象要回收的时候,CLR一样调用了析构函数,那么咱们的Dispose有什么意义呢?实际上一般提供了Dispose形式的, 再Dispose方法内部的最后一般有那么一句

GC.SupproseFinalize(this),也就是告诉CLR:好了,我已经本身去释放非托管资源了,不须要你来释放了,在垃圾回收的时候,你直接把对象回收了,不要给我再来添加到

“终结可达队列”了。因此这样当已经调用过Dispose操做的,就不会出现2次回收才释放对象的状况。

一般相似下面这样的代码

public class MyClass:IDispose

{  
     ~MyClass(){
    Dispose(false);//这个析构器是CLR调用的,默认仍是写上,防止未手动释放时,CLR能够把非托管释放
      }

    public void Close(){
         Dispose(true);
     }

     public void Dispose(){
    Dispose(true);
     }

     private void Dispose(bool bool1){
      if(bool1){
      //写一点本身能控制的代码
            }
           //释放非托管资管
         GC.SupposeFinalize(this)//告诉CLR,释放过了,不要再添加到“终结可达队列”,直接销毁内存
     }
}
相关文章
相关标签/搜索