C# IDisposable接口与using关键字


1. 简介

C#中的IDisposable接口就是一种非常有用且非常常用的接口,该接口要求类实现Dispose()方法,在该方法中释放占用的资源。如果在析构函数中释放资源要等到垃圾回收时,太晚了。但是手动调用Dispose方法稍微有点麻烦,而且也怕忘了调用,这样资源也得不到及时释放,所以可以使用using关键字,using关键字代码块的末尾会自动调用Dispose方法。

2.

什么是资源C#中的每一种类型都是一种资源,而资源又分为托管资源和非托管资源

托管资源:由CLR管理分配和释放的资源,也就是我们直接new出来的对象;

非托管资源:不受CLR控制的资源,比如Windows内核对象、文件操作、数据库连接、socket、Win32API、网络等。非托管资源有部分.NET的垃圾回收也帮我们实现了,如果要让.NET垃圾回收帮我们释放非托管资源,该如何去实现。

      假设我们要使用FileStream,我们通常的做法是将其using起来,或者是更老式的try…catch…finally…这种做法,因为它的实现调用了非托管资源,所以我们必须用完之后要去显式释放它,如果不去释放它,那么可能就会造成内存泄漏。

     非普通类型包含了非托管资源,实现了IDisposable,但又包含有自身是托管资源,所以需要手动清理。

在CLR托管的应用程序中,有一个“根”的概念,类型的静态字段、方法参数以及局部变量都可以被作为“根”存在(值类型不能作为“根”,只有引用类型才能作为“根”)。

在垃圾回收的过程中,GC会沿着线程栈扫描“根”如果没有发现引用这个局部变量,不管你是否已经显式的置为null都意味着“根”已经被停止,然后GC就会发现该根的引用为空,就会被标记为可被释放

如果我们的项目是在Release配置下的,上面的代码压根就不会被编译到dll。但是在静态字段或属性另一种情况下,就有必要将对象赋值为null。是因为类型的静态字段一旦被创建,就被作为“根”存在,基本上不参与GC,所以GC始终不会认为它是个垃圾,而非静态字段则不会有这样的问题。所以在实际工作当中,一旦我们感觉静态变量所占用的内存空间较大的时候,并且不会再使用,便可以将其置为null。