C# Dispose模式

目的

71ceb0414694189116b0b6d4f656f337.png

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

必须遵循的事实

fc23d38f65aa299953b777a8ef9f4183.png

1 .  托管资源释放:
  由另一线程的 gc 进行释放,当托管的对象没有被引用时,就会在“适当的时候”进行回收。
  如果定义了析构函数,回收的时候会调用析构函数(实际执行可能有差别),之后释放对象占用的内存。
  当类有析构函数时, gc 会分分两步来释放,如果没有析构函数或者指定不需要调用析构函数时,只需要一步就能释放。

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

方案

c4d016a869ee4af3cb7630b722bb1b60.png

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

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

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

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

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

手动调用Dispose() 可以释放所有资源,并且在 gc 标记不需要再调用析构函数,从而提高了效率。如果忘记调用Dispose(), 则当 gc 调用析构函数的时候也会把非托管资源释放掉。

参考代码

4b76dcf76a57fa2806541eef284b07ad.png

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;
    }
}

可能存在的疑问

d06c4ac198e8f903bac28f5cd939864b.png

a4144926e9708e74d0ffdc9d2fa540ab.png

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

90aa7a694027325e8d7d234d9c386574.png

因为如果可以主动调用的时候,肯定此对象不是死对象,也不会被回收,因此不会同时调用到哪里不太对,但又说不上来。

a71f787cbdafd9f83eb7c85449087c1a.png

2b32cc8b4596cfcab9497e085835784b.png

7b618af3b96c142b27e21bf19050540b.png

outside_default.png

outside_default.png

outside_default.png

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

outside_default.png

outside_default.png

outside_default.png

outside_default.png

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

outside_default.png

outside_default.png

outside_default.png

c3356ec46211f29c950d6c31e8faa70b.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值