知识大全 .net中非托管资源如何清理

Posted 资源

篇首语:万事须己运,他得非我贤。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 .net中非托管资源如何清理相关的知识,希望对你有一定的参考价值。

  背景这两天帮助其它项目组Review代码 发现有些地方实现了IDispose接口 同时也发现了一些关于IDispose的问题:

          A类型实现了IDispose接口 B类型里面含有A类型的字段 B类型没有实现IDispose接口

          一个类里面实现了Finalize终结器 同时也实现了IDispose接口 但在Dispose方法里面没有调用GC SuppressFinalize(this)方法

  下面我对以上两个问题分别分析一下 并提出解决方案

  问题 :如果A类型里面有非托管资源需要在实现的IDispose接口里面释放 由于B类型没有实现IDispose接口 B类型的使用者要想释放A类型的非托管资源并不方便 这样的话 就有可能忘记了释放A类型的非托管资源

  解决方案:实现B类型的IDispose接口 在Dispose方法里面调用A类型的Dispose方法 这样 B类型的使用者在调用B类型Dispose的同时 就把A类型的Dispose也调用了

  问题 :在Dispose方法里面没有调用GC SuppressFinalize(this)方法 会有什么问题呢 这样会导致垃圾回收器不能对这个类型的对象及时回收 当GC开始工作的时候 它首先将没有终结器的垃圾对象从内存中移除 有终结器的所有对象则添加到一个垃圾队列当中 GC会调用一个新线程来执行这些对象的终结器 当终结器执行完毕后 这个对象会从队列中被移除 这个对象在队列中移除之后 当GC再次开始工作的时候 这个对象才能够被回收 所以有终结器的对象会比没有的在内存中保留更长的时间 在后面我会对这里再详细的描述一下

  解决方案:

  在Dispose方法中调用GC SuppressFinalize(this)方法 这样的话 就不会把有终结器的对象则添加到垃圾队列当中

  切入正题 <中,非托管代码清理有两种方式:finalize方式和dispose方式.< p>

  Finalize方式:通过对自定义类型实现一个Finalize方法来释放非通过资源.

  2.0开始,C#编译器不能对Finalize进行显示的调用和重写,必须使用析构函数来实现它.

  class A

  

  ~A()

  

  释放资源;

  

  

  上面的代码就是通过Finalize方式来释放资源的跟C++用析构函数释放资源的代码很象.

  但是它实现方式和C++不同,因为它是由垃圾回收器来管理内存的.

  大家看到了,用Finalize方式释放非托管资源很简单,但是如果你了解了他的实现方式,你可能就不会选择用它来释放非托管资源.

  那Finalize方式内部是如何实现的呢?

  当GC(垃圾回收器)开始工作的时候,它首先将没有终结器的垃圾对象从内存中移除,有终结器的所有对象则添加到一个终止化队列当中。tW.WingwiT.CoMGC会调用一个新线程来执行这些对象的终结器。当终结器执行完毕后,这些对象会从队列中被移除。这时候由于这些对象在第一次检测到的时候没有被释放,它们将会进入第1代对象,直到GC检测到第0代对象和第1代对象再次充满时,这时候GC才会把刚才那些对象释放掉,所以有终结器的对象会比没有的在内存中保留更长的时间。

  提示:垃圾回收器把托管堆中的对象分为3代,分别是0,1,2.一般分配为:0代约256K,1代约是2MB,第2代约是MB,代龄越高,容量就越大,显然效率也就越低.首先被添加到托管堆中的对象被定为第0代,当第0代充满时,就会执行垃圾回收,未被回收的对象代领将提升1代.

  由于以上原因应该避免仅使用Finalize方式释放非托管资源.

  Dispose模式:在自定义类中实现IDispose接口,在接口中

  的Dispose方法中对非托管资源进行释放.闲话少说,上代码

  public class MyResourceRelease: IDisposable

  

  ///

  /// 保证资源只用释放一次

  ///

  private bool _alreadyDisposed = false;

  ///

  ///

  ///

  /// 用来判断释放资源的类别(托管和非托管)

  protected virtual void Dispose(bool isDisposing)

  

  if(_alreadyDisposed)

  

  return;

  

  if(isDisposing)

  

  //释放托管资源

  

  //释放非托管资源

  _alreadyDisposed = true;

  

  public void Dispose()

  

  Dispose(true);

  

  

  上面的代码就是用Dispose方式释放资源的方法.因为上面自定义的Dispose(bool isDisposing)方法是virtual的,所以还可以在派生类里面对它进行override

  public class MyDerivedResource: MyResourceRelease

  

  private bool _disposed = false;

  protected override void Dispose(bool isDisposing)

  

  if(_disposed)

  

  return;

  

  try

     

  if(isDisposing)

  

  //释放托管资源

  

  //释放非托管资源

  _disposed = true;

  

  finally

  

  base.Dispose(isDisposing);

  

  

  

  这样可以确保释放继承链上所有对象的引用资源,在整个继承层次中传播Dispose模式.

  思考

  那用Dispose方式非托管资源就是最好的方法了吗?

  其实不然,因为类型实现了IDispose接口,这个类的使用者必须显示调用Dispose方法,或者在创建该类型对象的时候使用using关键字,对于一些粗心的使用者可能会忘记调用Dispose方法,或者没有使用using关键字,这样就导致了非托管资源没有释放的后果.

  最佳方案

  同时实现终结器和Dispose方式.这样对于细心的使用者直接显示调用Dispose方法会提高垃圾回收的性能,对于粗心的使用者虽然忘记了调用Dispose方法,但也不至于使得非托管资源得不到释放.

  注意这里用到了GC. SuppressFinalize(this)方法.

  代码如下:

  public class MyResourceRelease: IDisposable

  

  ~MyResourceRelease()

  

  Dispose(false);

  

  ///

  /// 保证资源只用释放一次

  ///

  private bool _alreadyDisposed = false;

  ///

  ///

  ///

  /// 用来判断释放资源的类别(托管和非托管)

  protected virtual void Dispose(bool isDisposing)

  

  if(_alreadyDisposed)

  

  return;

  

  if(isDisposing)

  

  //释放托管资源

  

  //释放非托管资源

  _alreadyDisposed = true;

  

  public void Dispose()

  

  Dispose(true);

  //阻止GC把该对象放入终结器队列

  GC.SuppressFinalize(this);

  

cha138/Article/program/net/201311/11606

相关参考

知识大全 C#清理非托管对象[1]

C#清理非托管对象[1]  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  这两天帮助其它项目组Re

知识大全 深入.NET托管堆(managedheap)(1)

深入.NET托管堆(managedheap)(1)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 

知识大全 浅谈.NET互操作技术 重点托管代码

浅谈.NET互操作技术重点托管代码  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  多年来在程序设

知识大全 ASP.NET技巧:非托管COM组件的使用

ASP.NET技巧:非托管COM组件的使用  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  众所周

知识大全 调用非托管dll常出现的bug及解决办法

  C和C++有很多好的类库的沉淀在NET中完全抛弃它们而重头再来是非常不明智的也是不现实的所以我们经常需要通过Pinvoke来使用以前遗留下来的非托管的dll就NET中使用非托管的dll经验而言经常

知识大全 VC.NET扩展Windows磁盘清理工具的功能

VC.NET扩展Windows磁盘清理工具的功能  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  

知识大全 ASP.NET中Control基类清理页面状态

ASP.NET中Control基类清理页面状态  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  控

知识大全 微软同步框架中的自定义数据同步基础

  MicrosoftSyncFramework(MSF)为我们提供了进行同步应用开发的基础框架和API这些API即有基于托管代码的也有基于非托管代码的也就是说我们既可以开发基于NET平台使用托管AP

知识大全 vs.net中web services入门

  Visual中的XMLWebservices入门  目录  简介用托管代码编写的XMLWebservices使用VisualStudio创建XMLWebservices使用VisualStudio

知识大全 哪个托管伙食好点,我们孩子要换托管

哪个托管伙食好点,我们孩子要换托管?如果是因为伙食问题,建议别给孩子换托管,或者说想知道这个托管机构的伙食到底如何,孩子太小,不能养成他挑食的习惯。所以只要伙食好,营养达到就行,不能让孩子养成挑食的坏