对.Net 垃圾回收的C#编程相关方面(Finalize 和Dispose(bool disposing)和 Dispose())的一些理解体会
发布日期:2021-09-28 09:31:53 浏览次数:1 分类:技术文章

本文共 2413 字,大约阅读时间需要 8 分钟。

 

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

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

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

  1. Finalize是CRL提供的一个机制, 它保证如果一个类实现了Finalize方法,那么当该类对象被垃圾回收时,垃圾回收器会调用Finalize方法.而该类的开发者就必须在Finalize方法中处理 非托管资源的释放. 但是什么时候会调用Finalize由垃圾回收器决定,该类对象的使用者(客户)无法控制.从而无法及时释放掉宝贵的非托管资源.由于非托管资源是比较宝贵了,所以这样会降低性能.
  2. 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())的使用经历可以加深对他们的理解.谢谢!

转载地址:https://blog.csdn.net/gooer/article/details/2866290 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:显式和隐式实现接口
下一篇:.net内存回收与Dispose﹐Close﹐Finalize方法

发表评论

最新留言

能坚持,总会有不一样的收获!
[***.219.124.196]2024年03月28日 19时09分53秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

【面试篇】Java对象的hashCode()相同,equals()一定为true吗? 2019-04-26
【面试篇】Java中static和final关键字的作用是什么? 2019-04-26
【面试篇】Java中接口和抽象类的区别是什么? 2019-04-26
【Java网络编程与IO流】Java中IO流分为几种?字符流、字节流、缓冲流、输入流、输出流、节点流、处理流 2019-04-26
【Java网络编程与IO流】Java中BIO、NIO、AIO的区别是什么? 2019-04-26
【Leetcode刷题篇】leetcode136 只出现一次的数字 2019-04-26
spring boot整合thymeleaf,支持JSP和HTML页面开发 2019-04-26
【Java网络编程与IO流】Spring boot整合SSE实现服务器实时推送流信息 2019-04-26
【Java网络编程与IO流】SpringBoot + WebSocket + Netty实现实时的服务器消息推送 2019-04-26
【Leetcode刷题篇】leetcode141 环形链表II 2019-04-26
【Leetcode刷题篇】leetcode160 相交链表 2019-04-26
【Leetcode刷题篇】leetcode169 多数元素 2019-04-26
【Leetcode刷题篇】leetcode461 汉明距离 2019-04-26
【Leetcode刷题篇】leetcode204 计数质数 2019-04-26
【Leetcode刷题篇】leetcode70 爬楼梯 2019-04-26
【Leetcode刷题篇】leetcode739 每日温度 2019-04-26
【Leetcode刷题篇】leetcode121买卖股票的最佳时机 2019-04-26
【面试篇】Java多线程并发-Java关键字volatile详解 2019-04-26
【面试篇】Java的代理模式-静态代理和动态代理详解 2019-04-26
【面试篇】 Java对象拷贝(对象克隆 对象复制) 2019-04-26