垃圾回收是一个只处理托管资源的不确定事件。把object = null后等着GC回收就行了。对于托管资源,垃圾收集就能很好的工作。
问题是:有些昂贵的非托管资源如何管理?
解决方法一:实现Finalize方法管理对象的清理。
包含Finalize方法的对象不同于那些不含此方法的对象。前者通常在堆中分配内存,重要的是指向它的指针放在“最终化队列”中。垃圾收集期间,GC扫描“最终化队列”,搜索不可达对象的指针,并将其移到"不可达队列"中。该队列中引用的对象仍存活,以便某个后台线程能扫描该队列,并对每个引用的对象执行Finalize方法。再次发生垃圾收集时才释放这些内存。
最好是创建一个析构函数代替Finalize,并将Finalize方法中代码放入析构函数。编译器将析构函数代码转化为一个提供异常处理的Finalize方法。其中还包含对基类的Finalize方法。
解决方法二:继承IDisposable接口
很明显第一种方法依赖GC所以释放的时间还是不确定,幸运的是,CLR提供了Dispose来通知对象完成清理。
可以实现IDisposable接口,在Dispose函数内写清理代码。让客户调用Dispose清理资源。这时又有两个问题:
1.若已经对象Dispose后又调用对象方法该怎么办?
很明显一个bool型IsDiposed字段控制使用,若已经Dispose则抛出异常(ObjectDisposedException)
2.不能保证客户会调用Dispose?
所以最好应该也实现Finalize(构造一个析构函数),当客户没有调用Dispose时让GC回收。一般Dispose函数和析构函数调用同一个清理资源的函数。
3.如果实现Finalize,那么在调用了Dispose后。如何保证GC不再参与回收资源(即GC不再调用Finalize)?
在Dispose函数内执行GC.SuppressFinalize(this);此静态方法可以通知GC不把对象放入不可达队列。这样就不会Finalize了。