从GC的SuppressFinalize方法带你深刻认识Finalize底层运行机制
如果你经常看开源项目的源码,你会发现很多dispose方法中都有这么一句代码: gc.suppressfinalize(this);
,看过一两次可能无所谓,看多了就来了兴趣,这篇就跟大家聊一聊。
一:背景
1. 在哪发现的
相信现在mysql在.net领域中铺的面越来越广了,c#对接mysql的mysql.data类库的代码大家可以研究研究,几乎所有操作数据库的几大对象:mysqlconnection,mysqlcommand,mysqldatareader以及内部的driver都存在 gc.suppressfinalize(this)
代码。
public sealed class mysqlconnection : dbconnection, icloneable { public new void dispose() { dispose(disposing: true); gc.suppressfinalize(this); } } public sealed class mysqlcommand : dbcommand, idisposable, icloneable { public new void dispose() { dispose(disposing: true); gc.suppressfinalize(this); } }
2. gc.suppressfinalize 场景在哪里
先看一下官方对这个方法的解释,如下所示:
// // summary: // requests that the common language runtime not call the finalizer for the specified // object. // // parameters: // obj: // the object whose finalizer must not be executed. // // exceptions: // t:system.argumentnullexception: // obj is null. [reliabilitycontract(consistency.willnotcorruptstate, cer.success)] [securitysafecritical] public static void suppressfinalize(object obj);
意思就是说: 请求 clr 不要调用指定对象的终结器,如果你对终结器的前置基础知识不足,那这句话肯定不是很明白,既然都执行了dispose,说明非托管资源都被释放了,怎么还压制clr不要调用finalize呢?删掉和不删掉这句代码有没有什么严重的后果,gc类的方法谁也不敢动哈。。。 为了彻底讲清楚,有必要说一下finalize整个原理。
二:资源管理
我们都知道c#是一门托管语言,它的好处就是不需要程序员去关心内存的分配和释放,由clr统一管理,这样编程门槛大大降低,天下攘攘皆为利来,速成系的程序员就越来越多~
1. 对托管资源和非托管资源理解
<1> 托管资源
这个很好理解,你在c#中使用的值类型,引用类型都是统一受clr分配和gc清理。
<2> 非托管资源
在实际业务开发中,我们的代码不可能不与外界资源打交道,比如说文件系统,外部网站,数据库等等,就拿写入文件的streamwriter举例,如下代码:
public static void main(string[] args) { streamwriter sw = new streamwriter("xxx.txt"); sw.writeline("...."); }
为什么能够写入文件? 那是因为我们的代码是请求windows底层的win32 api帮忙写入的,这就有意思了,因为这个场景有第三者介入,sw是引用类型受clr管理,win32 api属于外部资源和.net一点关系都没有,如果你在用完sw之后没有调用close方法的话,当某个时候gc回收了托管堆上的sw后,这给被打开的win32 api文件句柄再也没有人可以释放了,资源就泄露了,如果没看懂,我画张图:
三:头疼的非托管资源解决方案
1. 使用析构函数
很多时候程序员就是在使用完类之后因为种种原因忘记了手动执行close方法造成了资源泄露,那有没有一种机制可以在gc回收堆对象的时候回调我的一个自定义方法呢?如果能实现就
上一篇: Quickuse.Caching 快速应用.缓存组件
下一篇: JS高级---案例:验证密码的强度