建议47:即使提供了显式释放方法,也应该在终结器中提供隐式清理

本文详细介绍了C#中的Dispose模式及其在资源管理中的应用,解释了如何通过显式和隐式方法进行资源清理,以及如何利用终结器确保资源得到释放,避免内存泄漏。

建议47:即使提供了显式释放方法,也应该在终结器中提供隐式清理

在标准的Dispose模式中,我们注意到一个以~开头的方法,如下:

复制代码
        /// <summary>
        /// 必须,防止程序员忘记了显式调用Dispose方法
        /// </summary>
        ~SampleClass()
        {
            //必须为false
            Dispose(false);
        }
复制代码

这个方法叫做类型的终结器。提供类型终结器的意义在于,我们不能奢望类型的调用者肯定会主动调用Dispose方法,基于终结器会被垃圾回收这个特点,它被用作资源释放的补救措施。

在.NET中每次使用new操作符创建对象时,CLR都会为该对象在堆上分配内存。对于没有继承IDisposable接口的类型对象,垃圾回收器则会直接释放对象所占用的内存:而对于实现了Dispose模式的类型,每次创建对象的时候,CLR都会将该对象的一个指针放到终结列表中,垃圾回收器在回收该对象的内存前,首先将终结列表中的指针放到一个freachable队列中。同时,CLR还会分配专门的线程读取freachable队列,并调用对象的终结器,只有这个时候对象才会真正被识别为垃圾,并且在下一次进行垃圾回收时释放对象所占的内存。

 

可见,实现了Dispose模式的类型对象,起码要经过两次垃圾回收才能真正地被回收掉,应为垃圾回收机制会安排CLR调用终结器。基于这个特点,如果我们的类型提供了显式释放的方法来减少一次垃圾回收,同时也可以在终结器中提供隐式清理,以避免调用者忘记调用该方法而带来的资源泄漏。

注意:有的文档中,终结器也称为析构器。析构器的叫法沿袭了C++中的称谓,因为两者形式非常接近,但两者实现机制还是不太一致,所以后来微软确定这个方法在C#中的名称为终结器。

 

如果调用者已经调用Dispose方法进行了显式地资源释放,那么,隐式资源释放(就是终结器)就没有必要再运行了。FCL中的类型GC提供了静态方法SuppressFinalize来通知垃圾回收器这一点。

复制代码
        /// <summary>
        /// 实现IDisposable中的Dispose方法
        /// </summary>
        public void Dispose()
        {
            //必须为true
            Dispose(true);
            //通知垃圾回收机制不再调用终结器(析构器)
            GC.SuppressFinalize(this);
        }
复制代码

 

 

 

转自:《编写高质量代码改善C#程序的157个建议》陆敏技

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值