首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

【C#】-C#Dispose模式详细分析

目的:

为了及时释放宝贵的非托管资源和托管资源,并且保证资源在被gc回收的时候可以正确释放资源,同时兼顾执行效率

必须遵循的事实:

1 托管资源释放:

由另一线程的gc进行释放,当托管的对象没有被引用时,就会在“适当的时候”进行回收

如果定义了析构函数,回收的时候会调用析构函数(实际执行可能有差别),之后释放对象占用的内存。

当类有析构函数时, gc会分分两步来释放,如果没有析构函数或者指定不需要调用析构函数时,只需要一步就能释放

2 非托管资源必须显式释放

方案:

1.把资源释放都放在析构函数里。

可以保证资源都释放,但是由于gc调用时机的不确定性,导致宝贵的非托管资源无法及时释放。

2. 写个释放函数,手动是调用

如果忘了释放的话, 托管资源会被gc释放,但非托管资源就无法释放

3. Dispose模式。参考下面的代码

手动调用Dispose() 可以释放所有资源,并且在gc标记不需要再调用析构函数,从而提高了效率。

如果忘记调用Dispose(), 则当gc调用析构函数的时候也会把非托管资源释放掉

参考代码:

public interface IDisposable

{

  void Dispose();

}

public class DisposablClass : IDisposable

{

  //是否回收完毕

  bool _disposed;

  public void Dispose()

  {

      Dispose(true);

      GC.SuppressFinalize(this); //标记gc不在调用析构函数

  }

  ~DisposableClass()

  {

      Dispose(false);

  }

  private void Dispose(bool disposing)

  {

      if(_disposed) return; //如果已经被回收,就中断执行

      if(disposing)

      {

          //TODO:释放本对象中管理的托管资源

      }

      //TODO:释放非托管资源

      _disposed = true;

  }

}

可能存在的疑问

1. 既然gc是另外一线程执行的,为什么Dispose(bool)函数里不加锁?

答:因为如果可以主动调用的时候,肯定此对象不是死对象,也不会被回收,因此不会同时调用到

2. 为什么析构函数调用的dispose(false)不释放托管资源?

  答:因为析构函数由gc来调用,gc会依次释放所有的死对象(不可到达),释放的顺序是随机的,如果在一个对象的析构里调用了一个本次gc已经释放的对象,就会发生释放两次的错误。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20200609A001A100?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券