2.当终结线程遍历终结对象队列中的对象时,它调用每个对象的Finalize方法。Finalize是System.Object中一个虚方法的重写,但是在C#中显式重写这个方法是非法的,取而代之的是,要编写一个析构函数,这个析构函数就像是一个没有返回类型、没有访问修饰符、没有参数的方法,析构函数的标识符是类名前加一个"~".析构函数不能显式地在C#中调用,并且像构造函数一样,不能被继承。一个类只能有一个析构函数。
3.IDisposable接口
IDisposable接口的定义如下:
public interface IDisposable
{
void Dispose();
}
IDisposable接口只有一个方法,即Dispose方法。在这个方法的实现里完成了清理工作。当实现Dispose的时候,通常以终结器代码重用Dispose的方式来实现。这样,如果客户代码没有调用Dispose,终结器代码在终结的时候会调用它。对象实现IDisposable接口痛苦的另一个因素是,如果对象包含指向其他支持IDisposable的对象的引用,必须链式调用IDisposable。这使类设计更复杂,因为必须知道用作字段的类型是否实现了IDisposable,如果是,必须在这个类实现IDisposable,并确保调用Dispose方法。
Dispose方法调用了GC.SuppressFinalize,调用垃圾回收器的方法可以防止垃圾回收器终结对象。如果客户代码调用了Dispose方法,而且Dispose方法完全地清除了所有资源,包括终结器应该完成的所有工作,那么这个对象就没有必要在纠结.你可以调用SupressFinalize来防止这个对象终结.这个便利的优化有助于GC在所有引用都消失后及时地清除对象.
4.try{}finally{}
无论执行流程如何离开try块,即不管是通过一个返回语句正常返回还是抛出异常,finally块里的代码总会执行。可以把finally块看作是一种安全网,调用对象的Dispose正是在这个finally块内,无论发生什么,Dispose都会被调用。
5.using()
using 关键字有两个用途:
1、在程序开始处,声明程序中用到的命名空间,或者给命名空间定义别名;
2、在程序中,处理非托管对象,保证其正确释放资源;
6.资源在哪个类中被创建就应该在哪个类中清除.如果类中调用了其他基类中创建的资源,则应在基类中删除这些资源.
7.析构函数
析构函数是由垃圾回收器在清理对象时调用的.因为.NET中的托管对象都是由垃圾回收器自动定期清理的,所以如果一个类中只有托管对象,则垃圾回收器在回收该对象时会同时一次性清理掉该类中创建的托管对象,此种情况下不要编写析构函数(情况A)。
如果一个类中创建使用了非托管资源(如数据库连接)(情况B),此时应该使用析构函数,但也只是作为忘记调用Dispose()函数的一种备份机制。换言之,此时,应该先掉用Dispose()函数来删除资源.Dispose()函数由用户来调用.
在上面的情况A中,可以不调用Dispose()函数。但如果类中创建使用过一些较大的托管对象,最好尽快清除它们,此时可以在Dispose函数中删除它们,并由用户调用以尽快删除它们.
在情况B中,应该在Dispose()中删除非托管资源,并由用户调用Dispose()。此时,为防止垃圾回收器再次调用析构函数,应该在Dispose()中调用GC.SuppressFinalize(this)通知垃圾回收器,此对象已经不再需要执行析构函数以免重复执行。但如果用户忘记了调用Dispose(),则垃圾回收器仍然会执行析构函数,保证非托管资源会被清除。
8.托管和非托管资源
托管资源指的是.NET可以自动进行回收的资源,主要是指托管堆上分配的内存资源。托管资源的回收工作是不需要人工干预的,有.NET运行库在合适调用垃圾回收器进行回收。
非托管资源指的是.NET不知道如何回收的资源,最常见的一类非托管资源是包装操作系统资源的对象,例如文件,窗口,网络连接,数据库连接,画刷,图标等。这类资源,垃圾回收器在清理的时候会调用Object.Finalize()方法。默认情况下,方法是空的,对于非托管对象,需要在此方法中编写回收非托管资源的代码,以便垃圾回收器正确回收资源。
在.NET中,Object.Finalize()方法是无法重载的,编译器是根据类的析构函数来自动生成Object.Finalize()方法的,所以对于包含非托管资源的类,可以将释放非托管资源的代码放在析构函数。
注意,不能在析构函数中释放托管资源,因为析构函数是有垃圾回收器调用的,可能在析构函数调用之前,类包含的托管资源已经被回收了,从而导致无法预知的结果。