C#的每一个类型都代表一种资源,而资源又分为两类:

  • 托管资源  由CLR管理分配和释放的资源,即从CLR里new出来的对象。
  • 非托管资源  不受CLR管理的对象,如Windows内核对象,或者文件、数据库连接、套接字、COM对象等。

  如果类型用到了非托管资源,或者需要显式释放托管资源,那么需要让类型继承接口IDisposable。记住:如果类型需要显式释放资源,那么一定要继承IDisposable接口。如:

class SampleClass:IDisposable
{
private IntPtr nativeResource = Marshal.AllocHGlobal();//非托管资源
private Bitmap bitmap = new Bitmap(, );//托管资源
private bool isDisposed = false; //实现IDisposable中的Dispose方法
public void Dispose( )
{
Dispose(true);
GC.SuppressFinalize(this);//通知垃圾回收器不用再调用终结器
}
//不必要的方法,只是为了符合其他语言的规范
public void Close()
{
Dispose();
}
//必须的,防止程序员忘记显示调用Dispose方法(隐式清理)
~SampleClass()
{
Dispose(false);
}
//非密封类修饰用protected virtual,提醒子类必须实现自己的清理方法时注意到父类的清理工作
protected virtual void Dispose(bool isDisposing)
{
if(isDisposed)
{
return;
}
if(isDisposing)
{
//清理托管资源
if(bitmap != null)
{
bitmap.Dispose();
bitmap = null;
}
}
//清理非托管资源
if(nativeResource!=IntPtr.Zero)
{
Marshal.FreeHGlobal(nativeResource);
nativeResource = IntPtr.Zero;
}
isDisposed = false;
} public void SamplePublicMethod()
{
if(isDisposed)
{
throw new ObjectDisposedException("SampleClass", "SampleClass is disposed");
}
//代码
}
}

  继承IDisposable接口,可以使用using语法糖。在using语句代码块内,可以使用声明的对象,当语句离开代码块后,系统自动释放资源:

//使用using方法,当语句离开代码块后,using内的对象自动释放
using (SampleClass sample = new SampleClass())
{
//……
}
//以上代码相当于下面的代码
SampleClass sample0 = new SampleClass();
try
{
//……
}
finally
{
sample0.Dispose();
}

  在SampleClass中,存在一个终结器(C++中叫析构器)。其意义在于,调用者可能并不会主动调用Dispose方法,而终结器会被垃圾回收器调用调用,所以它作为释放资源的补救措施。

  在CLR中,每new一个对象时,就会为该对象在堆上分配内存,如果不再被引用,就会回收它们的内存。如果没有实现IDisposable接口的类型对象,垃圾回收器会直接释放对象所占内存;如果实现了,每次创建对象时,CLR会将该对象的一个指针放到终结列表中,垃圾回收器在回收对象前会首先将终结列表中的指针放入一个freachable队列。同时,CLR会分配一个线程管理freachable队列,调用对象终结器,只有此时,对象才会被真正标识为垃圾,并在下一次进行垃圾回收时释放对象所占内存。即:实现IDisposable接口的类型,至少要经过两次垃圾回收才能真正释放掉内存。其中Dispose方法中的GC.SuppressFinalize()方法用于在显示释放资源后,通知垃圾回收器不用再调用终结器(隐式回收)释放资源。

  在实现IDisposable接口时,其Dispose()方法并没有做实际的清理工作,但提供了带bool参数的受保护的虚方法。因为该类型可能被其他类继承,如果子类实现自己的Dispose模式,受保护的虚方法可以提醒子类:在实现自己的清理方法时,需要注意父类的清理工作(base.Dispose方法)。

  真正撰写资源释放代码的虚方法有一个bool参数,但是在显示释放资源(true)与隐式释放资源(false)调用中传入的参数不同。表明:隐式清理时,只需要处理非托管资源就行。托管资源中的普通类型不需要手动清理,而非普通类型需要手动清理。

  Dispose模式设计思路:如果调用者显示调用了Dispose方法,那么类型按部就班释放自己的全部资源,然后通知垃圾回收器不需要再释放(GC.SuppressFinalize()方法);而忘记调用Dispose方法,那么类型就假定自己的所有托管资源会全部交给垃圾回收器回收,不需要手动清理。

最新文章

  1. Tomcat学习记录
  2. Python开发问题和解决方案汇集
  3. android retrofit @Query用法
  4. 怎么解决tomcat占用8080端口问题图文教程(转)
  5. HDU 5002 Tree LCT 区间更新
  6. struts2 修改action的后缀
  7. jQuery2.x源码解析(DOM操作篇)
  8. Linux命令之文件处理
  9. 1分钟选好最合适你的JavaScript框架
  10. valgrind安装与使用
  11. Asp.Net 之 Web.config 配置文件详解
  12. luogu2046[NOI2010]海拔 对偶图优化
  13. 正则表达式(java)
  14. CentOS下多网卡绑定多IP段时导致只有一个会通的问题解决
  15. 基于Cookie的购物车
  16. Guideline 2.5.1 - Performance - Software Requirements
  17. 乱序字符串anagrams
  18. linux 定时任务 crontab 详细解释(转)
  19. js中的冒泡排序
  20. BestCoder Round #1 第二题 项目管理

热门文章

  1. Rhythmk 学习 Hibernate 08 - Hibernate annotation 关联关系注解
  2. vb6 的关机代码
  3. 3 MySQL数据库--初识sql语句
  4. Thymeleaf 表达式工具类
  5. Jmeter Http接口性能测试
  6. MyBatis 动态SQL注意事项
  7. Shder中实现TintColor
  8. Python_03-数据类型
  9. 101. Symmetric Tree (Tree, Queue; DFS, WFS)
  10. 两个链表的交叉 · Intersection of Two Linked Lists