C#里的资源Dispose

注:这里的文章从"Zendy---勿在浮沙筑高台---"复制,目的是让我有一个比较充分的对这个问题的认识.

文章标题:对.Net 垃圾回收的C#编程相关方面(Finalize 和Dispose(bool disposing)和 Dispose())的一些理解体会

原文章地址:http://www.cnblogs.com/caomao/archive/2006/10/03/152505.html

 

Finalize 和Dispose(bool disposing)和 Dispose() 的相同点:

这三者都是为了释放非托管资源服务的.

Finalize 和 Dispose() 和Dispose(bool disposing)的不同点:

Finalize是CRL提供的一个机制, 它保证如果一个类实现了Finalize方法,那么当该类对象被垃圾回收时,垃圾回收器会调用Finalize方法.而该类的开发者就必须在Finalize方法中处理 非托管资源的释放. 但是什么时候会调用Finalize由垃圾回收器决定,该类对象的使用者(客户)无法控制.从而无法及时释放掉宝贵的非托管资源.由于非托管资源是比较宝贵了,所以这样会降低性能.
Dispose(bool disposing)不是CRL提供的一个机制, 而仅仅是一个设计模式(作为一个IDisposable接口的方法),它的目的是让供类对象的使用者(客户)在使用完类对象后,可以及时手动调用非托管资源的释放,无需等到该类对象被垃圾回收那个时间点.这样类的开发者就只需把原先写在Finalize的释放非托管资源的代码,移植到Dispose(bool disposing)中.  而在Finalize中只要简单的调用 "Dispose(false)"(为什么传递false后面解释)就可以了.
这个时候我们可能比较疑惑,为什么还需要一个Dispose()方法?难道只有一个Dispose(bool disposing)或者只有一个Dispose()不可以吗?
答案是: 
        只有一个Dispose()不可以. 为什么呢?因为如果只有一个Dispose()而没有Dispose(bool disposing)方法.那么在处理实现非托管资源释放的代码中无法判断该方法是客户调用的还是垃圾回收器通过Finalize调用的.无法实现 判断如果是客户手动调用,那么就不希望垃圾回收器再调用Finalize()(调用GC.SupperFinalize方法).另一个可能的原因(:我们知道如果是垃圾回收器通过Finalize调用的,那么在释放代码中我们可能还会引用其他一些托管对象,而此时这些托管对象可能已经被垃圾回收了, 这样会导致无法预知的执行结果(千万不要在Finalize中引用其他的托管对象).

 

        所以确实需要一个bool disposing参数, 但是如果只有一个Dispose(bool disposing),那么对于客户来说,就有一个很滑稽要求,Dispose(false)已经被Finalize使用了,必须要求客户以Dispose(true)方式调用,但是谁又能保证客户不会以Dispose(false)方式调用呢?所以这里采用了一中设计模式:重载  把Dispose(bool disposing)实现为 protected, 而Dispose()实现为Public,那么这样就保证了客户只能调用Dispose()(内部调用Dispose(true)//说明是客户的直接调用),客户无法调用Dispose(bool disposing).

范例如下:

public class BaseResource: IDisposable
{
  //析构函数自动生成 Finalize 方法和对基类的 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(),提高了非托管资源的使用效率并提升了系统性能

可以参考SqlConnection对象的New, Open, Close(内部调用Dispose())的使用经历可以加深对他们的理解.谢谢!

 

时间: 2024-08-20 00:48:05

C#里的资源Dispose的相关文章

magento 1.4 -- 后台权限里角色资源无法翻译的bug及解决方案

         在翻译1.4的时候发现后台系统->权限->角色菜单下,角色资源的设置选项全部为英文,并且无论我怎么折腾翻译包都无法将之翻译,想到之前后台分类页和产品页字段名不能翻译的bug,这里应该也是同样的原因.   打开文件/app/code/core/Mage/Adminhtml/Block/Permissions/Tab/Rolesedit.php,找到   $item['text']= (string)$node->title; 修改为 $item['text']= $thi

如何读取dll里资源文件 的几种方法

问题描述 一.当前程序集System.Xml.XmlDocumentdoc=newSystem.Xml.XmlDocument();//xml直接嵌入程序集读取的方法System.IO.Streamsm=Assembly.GetExecutingAssembly().GetManifestResourceStream("XW.Common.Address.xml");doc.Load(sm);//直接将流转成xmlbyte[]bs=newbyte[sm.Length];sm.Read(

从资源文件里加载文件(C#)

加载 1.概述: 资源文件很早就有了,在.Net时代里这个东西也不算稀奇,在进行多国语言化的时候通常把不同翻译的文字存放到资源包里.以前资源文件除了放字符串以外,还可以放文件.不过在C#的工程里面,资源管理面板是空的(vc++工程里资源面板可以使用),无法直接编辑资源属性,不过每个WinForm都会带一个.resx的文件,这个文件就是WinForm的资源文件.如果通过添加新项目的方法,给工程里添加资源文件的话,产生的也是.resx文件.估计.resx文件是.net给c#新设计的资源文件格式..r

资源无限的站群 你同样也可以拥有

对于站群的好处,相信站长朋友都知道.因为它是不少人的赚钱利器,互联网上有不少靠站群发财的案例,像之前的闷头赚钱的"左旋哥",还有动不动就出现的什么"站群月入几W的".因为站群盈利可观,所以到目前,站群依旧在站长圈非常的流行.目前运用最广泛的就是站群链轮了,这是众多操作站群站长抢占关键词的手法.用多个网站去优化同样一个关键词,其效果会相当明显,当然所承担的风险也会比较大.但是无论是推广还是收录,站群的效果是不容置疑的. 比较遗憾的就是,对于大多数站长来说,站群的门槛稍

利用Windows 7资源监视器发现潜伏木马

Windows 7在安全性上大大加强,特别值得一提的就是Windows 7任务管理器里的资源监视器,通过资源监视器可以发现潜伏的木马病毒. 在Windows 7里打开任务管理器,在性能页,点击资源监视器,再切到网络页.可以清楚的观察正在使用的网络资源进程,本地端口.远程端口.远程IP.发送和接收的数据量.

如何在C#中创建和使用资源文件

在C#中可以使用. Resources文件来保存各种类型的文件.下面我就举例说明如何创建和使用资源文件.首先是创造一个资源文件 System.Resources.ResourceWriter myResource = new System.Resources.ResourceWriter("you.resources"); myResource.AddResource("yangming", Image.FromFile("F:\\ym.jpg"

APK 里有什么?

本文讲的是APK 里有什么?, 如果我给你一份 Android 应用的源码然后请你提供关于 minSdkVersion, targetSdkVersion, permissions, configurations 等 Android 应用相关的信息,相信几乎每个有 Android 开发经验的人都能在短时间内给出答案.但如果我给你一个 Android 应用的 APK 文件然后让你给出同样的信息呢?乍一想可能会有点棘手. 事实上我就遇到了这样的情况,尽管我很早就知道 aapt 这类工具的存在,但当我

[C#]MemoryStream.Dispose之后,为什么仍可以ToArray()?

目录 概述 MemoryStream分析 总结 概述 事件起因,一哥们在群里面贴出了类似下面这样的一段代码: 1 class Program 2 { 3 static void Main(string[] args) 4 { 5 byte[] buffer = File.ReadAllBytes("test.txt"); 6 MemoryStream ms = new MemoryStream(buffer); 7 ms.Dispose(); 8 Console.WriteLine(m

Kubernetes:理解资源的概念

本文讲的是Kubernetes:理解资源的概念[编者的话]本文描述了 Kubernetes 资源模型的工作原理,为什么你应该总是限制容器资源,以及如何才能真正做到. 不知你是否已清楚,Kubernetes 是支持 Docker 和 rkt(当前是这两种)的容器调度系统.除了下面这些优美的特性,比如简易部署,配置管理,服务发现,等等,它还允许我们以一种更高效的方式来管理计算资源.本文将阐述如下问题,Kubernetes 资源模型如何工作,为什么你应该总是限制容器资源,以及如何才能正确做到. 资源管