C#如何释放未托管资源

在C#里面有2种机制来释放未托管资源:

  • 声明一个析构函数(或终结器),作为类的一个成员
  • 在类中执行System.IDisposable接口

析构函数

下面这段代码是一段带有析构函数的简单代码:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text; 



namespace MemRelease

{

    class Program

    {

        ~Program()

        {

            // Orders.

        } 



        static void Main(string[] args)

        {

        }

    }

} 

在IL DASM中,你会发现并没有这个析构的方法。C#编译器在编译析构函数时,会隐式地把析构函数的代码编译为Finalize()方法的对应代码,确保执行父类的Finalize()方法 看下这段代码中对于析构函数的编译:

.method family hidebysig virtual instance void 

        Finalize() cil managed

{

  // Code size       14 (0xe)

  .maxstack  1

  .try

  {

    IL_0000:  nop

    IL_0001:  nop

    IL_0002:  leave.s    IL_000c

  }  // end .try

  finally

  {

    IL_0004:  ldarg.0

    IL_0005:  call       instance void [mscorlib]System.Object::Finalize()

    IL_000a:  nop

    IL_000b:  endfinally

  }  // end handler

  IL_000c:  nop

  IL_000d:  ret

} // end of method Program::Finalize 

 

是一个try…finally的结构,

try



{



// destructor implementation



}



finally



{



base.Finalize();



}



~Program()析构函数中执行的代码封装在Finalize()方法的一个try块中。对父类Finalize()方法的调用放在finally块中,确保该调用的执行。

 

使用析构函数来释放资源有几个问题:

  1. 与C++析构函数相比,C#析构函数的问题是他们的不确定性。在删除C++对象时,其析构函数会立即执行,但是由于垃圾收集器的工作方式,无法确定C#对象的析构函数何时执行。
  2. C#析构函数的执行会延迟对象最终从内存中删除的时间。有析构函数的对象需要2次处理才能删除:第一次调用析构函数时,没有删除对象,第二次调用才真正删除对象。


IDisposable接口

在C#中,推荐使用System.IDisposable接口替代析构函数。IDisposable接口定义一个模式,为释放未托管的资源提供了确定的机制,并避免产生析构函数固有的与垃圾函数器相关的问题。

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;



namespace MemRelease

{

    class Program : IDisposable

    {

        public void Dispose()

        {

            // implementation

        }        



        static void Main(string[] args)

        {

        }

    }

}

假定有一个类ResourceGobbler,它使用某些外部资源,且执行IDisposable接口。如果要实例化着各类的实例,使用它,然后释放它,就可以使用下面的代码。

ResourceGobbler theInstance = new ResoucrGobbler();



// do your processing



theInstance.Dispose();

如果加入异常处理:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;



namespace MemRelease

{

    public class ResourceGobbler : IDisposable

    {

        public void Dispose()

        {

            //implementation

        }

    }



    class Program 

    {        

        static void Main(string[] args)

        {

            ResourceGobbler theInstance = null;



            try

            {

                theInstance = new ResourceGobbler();

                // do your processing

            }

            finally

            {

                if (theInstance != null)

                {

                    theInstance.Dispose();

                } 

            }

        }

    }

}

即使在处理过程中出现异常,这个版本也可以确保总是在theInstance上调用Dispose(),总能释放有theInstance使用的资源。

 

C#提供了一种语法,可以确保执行IDisposal接口的对象的引用超出作用域时,在该对象上自动调用Dispose().

using (ResourceGobbler theInstance =  new ResourceGobbler());

{

    // do your processing

}

你可能感兴趣的:(C#)