C#资源释放及Dispose、Close和析构方法

 

备注:此文的部分观点有误,之所以仍旧保留本文,是需要在后期给出一个勘误版。正确的版本在这里“C#中标准Dispose模式的实现


一:什么是资源

在开始本文前,需要一些准备知识。首先要提出“什么是资源”。在CLR出来之后,Windows系统资源开始分为“非托管资源”和“托管资源”。

非托管资源是指:所有的Window内核对象(句柄)都是非托管资源,如对于Stream,数据库连接,GDI+的相关对象,还有Com对象等等,这些资源并不是受到CLR管理;

托管资源是指:由CLR管理分配和释放的资源,即由CLR里new出来的对象。

其次再来讲,资源的释放方式。

非托管资源:需要显式释放的,也即需要你写代码释放;

托管资源:并不需要显式释放,但是如果引用类型本身含有非托管资源,则需要进行现实释放;

二:显式释放的C#实现

显式释放的C#实现,由C#语法支持的有:

1:实现IDisposable接口的Dispose方法;

2:析构方法(终结器);

不由C#语法支持,但是约定支持的显式释放是:

3:提供显示释放方法,比如常用的Close方法;

三:Dispose、Close和析构方法异同点

但是,还需要区分这3种方式的异同点。首先,你无法调用析构方法。析构方法是由垃圾回收机制进行调用的。换句话来说,就是你不知道析构方法被调用的时机。严格意义上来说,它只是作为资源释放的一个补救措施。

资源释放的一个正确的措施是为类型实现IDisposable接口的Dispose。当你需要释放类型的资源的时候,应该显示的调用Dipose方法。当然,这里还有一个C#的语法糖,就是使用using程序块,在离开using程序块的时候,CLR会自动调用类型所创建对象的Dipose方法。

可能有人会问道,既然可以通过Dispose方法的方式来进行资源的释放,为什么有些类型还需要提供一个Close方法。这里面的区别,或者说约定在于,如果你仔细观察这些类型:他们基本都只公开了Close方法,他们都实现了IDisposable,但都隐藏了Dispose方法。以Socket这个类为例,它:

1:提供public void Close()

public void Close()
{
//….
((IDisposable)this).Dispose();
//….
}

2:提供显式void IDisposable.Dispose()

void IDisposable.Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}

3:提供protected virtual void Dispose(bool disposing)。真正的资源释放的代码放在这里。

所以理论上来将,提供Close方法最终还是使用的Dispose方法,之所以这么做,是因为这些类型出于显式实现IDisposable的因素,在调用这些Dispose方法的时候,必须完成一次转型,如:

((IDisposable)new A()).Dispose();

为了避免转型,同时也为了避免不熟悉C#语法的开发人员更直观的释放资源,提供了Close方法。

在上文的例子中,你可能已经注意到IDisposable.Dispose这个方法中,包含一句: 

GC.SuppressFinalize(this); 

这是告诉CLR,在进行垃圾回收的时候,不用再继续调用析构方法(终结器)了。是的,因为你已经手动释放资源了。这也从另一个方面验证了析构方法只是作为资源释放的补救机制。因为假设你忘记Close或者Dispose了,CLR会在垃圾回收的时候为你做这件事。查看Socket的析构函数,你会很好的理解这一点。

~Socket()
{
this.Dispose(false);
}

是的,析构方法调用的也是Dispose。

备注1:本文带来几个争论

1:托管资源本身是否需要显式释放。答案显然是:不需要;

2:如果引用类型对象不再需要,是否需要显式=null;答案是:即使不这样做,GC也会进行垃圾回收。

3:将托管资源分为引用类型资源和值类型资源这种分类方法是有问题的,或者说是错误的。正确的分类法应该是栈资源和堆资源。线程栈中存放的是方法的实参和方法内部的局部变量。堆上存放的是类型对象本身及对象的两个额外成员:类型对象指针和同步块索引。

4:Dispose方法本身是用来让你放置资源清理代码的。显然,一个空方法并不代表清理工作本身,真正执行清理工作的是你具体的代码。

备注2:推荐Dipose模式实现

如:基类

代码

class ClassShouldDisposeBase : IDisposable
{
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}

protected virtual void Dispose(bool disposing)
{
if (disposing)
{
//执行基本的清理代码
}
}

~ClassShouldDisposeBase()
{
this.Dispose(false);
}

}

子类:

代码

class ClassShouldDispose: ClassShouldDisposeBase
{
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// 执行子类清理代码
// 如有必要,执行base.Dispose(disposing);
}
else
{
// 如有必要,执行base.Dispose(disposing);
}
}

public void Close()
{
//调用本类或者基类的Dispose方法
//其它代码
}
}

C#资源释放及Dispose、Close和析构方法相关推荐

  1. 有关Dispose,Finalize,GC.SupressFinalize函数-托管与非托管资源释放的模式

    //这段代码来自官方示例,删除了其中用处不大的细节using System; using System.ComponentModel;/**** 这个模式搞的这么复杂,目的是:不管使用者有没有手动调用 ...

  2. c#中的非托管资源释放 (Finalize和Dispose)

    c#中的非托管资源释放 (Finalize和Dispose) 收藏 在了解Finalize和Dispose之前,我们需要了解两个概念,一个是托管资源,一个非委托资源. a.其中托管资源一般是指被CLR ...

  3. C#中的非托管资源释放(FinalizeDispose)

    在了解Finalize和Dispose之前,我们需要了解两个概念,一个是托管资源,一个非委托资源. a.其中托管资源一般是指被CLR控制的内存资源,这些资源的管理可以由CLR来控制,例如程序中分配的对 ...

  4. C#内存泄露与资源释放 经验总结

    本文链接:http://blog.csdn.net/yokeqi/article/details/41083939 C#相比其他语言,拥有强大的垃圾回收机制,但并不是这样,你就可以对内存管理放任不管, ...

  5. VC++ - 各种DC及DC资源释放

    2013-04-18 16:58:57|  分类: GDI |  标签:cclientdc与cpaintdc  dc释放  dc  |字号 订阅 CClientDC dc(this); CPaintD ...

  6. Winform开发之窗体显示、关闭与资源释放

    Winform开发之窗体显示.关闭与资源释放 Winform的窗体涉及到一般窗体(单文档窗体).MDI窗体.窗体之间的关系等,那么如果调用打开新窗体.如何关闭窗体.窗体资源的释放等都关系到软件运行的效 ...

  7. Java8 新的 try-with-resources 语句,自动资源释放

    读取文件后需要释放资源,对于占用内存比较大的,非常重要: (1)读取文件内存占用较多的优化方式: 一次读取部分处理完继续读取,可以有效的减少内存的占用: 使用RandomAccessFile可以从文件 ...

  8. 基于 Android NDK 的学习之旅-----资源释放

    基于 Android NDK 的学习之旅-----资源释放 做上一个项目的时候因为与C引擎交互频繁,有时候会突然莫名其妙的的整个应用程序直接挂掉.因为我是学Java 开始的,所以对主动释放内存没多大概 ...

  9. rhcs做HA时的资源释放脚本实现

    场景: CentOS6.3的二次封装版本,安装hortonworks的hadoop发行版,并按照其官方文档实现高可用,但无fence设备支持,因此导致断网和断电测试时,备用HA节点无法得到资源释放的通 ...

最新文章

  1. makefile多目录的.c 格式.cpp混合编译
  2. termcap-1.3.1的configure.in文件逐行分析
  3. RabbitMQ pull与push的区别
  4. Fedora32升级Fedora33后无线网络无法连接的问题
  5. SURF 与 SIFT的共同点与区别
  6. 第二季-专题8-不用内存怎么行
  7. 【探索PowerShell 】【二】基本操作
  8. shell编程实战总结
  9. python下载音乐代码_使用python3下载网易云音乐歌单歌曲,附源代码
  10. 发一款资源查看,编辑软件,可以编辑dll,exe,res等后缀名的文件的小东东(Reshacker汉化版)
  11. 离散数学西电版复习笔记——第一章:命题逻辑
  12. Github年度百大框架排行榜
  13. msn一直登陆不上,没有办法只好启用meebo!
  14. 学习juca:Striped64(1.8)
  15. 计算机在职双证博士的学校,国内在职双证博士5所高校是哪些
  16. matlab注释分析高斯混合模型
  17. html5网页综合案例制作,网页开发与制作 HTML5页面元素及属性 2-21综合案例(6页)-原创力文档...
  18. 如何进行MySQL主从复制与读写分离的配置
  19. 51内核单片机实现Bootloader跳转到用户程序,要求两个程序都要支持中断
  20. 线路负荷较小时,线路元件是一个感性无功电源。为什么?

热门文章

  1. WPF MvvmLight简单实例(1) 页面导航
  2. Cobbler部署指南之Cobbler安装操作系统篇
  3. 使用Zabbix自带MySQL模板监控MySQL
  4. Python3学习之路
  5. MySQL------MySQL与SQLServer数据类型的转换
  6. Spring mvc3的ajax
  7. 运维工程师必备之MySQL数据的主从复制、半同步复制和主主复制详解
  8. 你真的了解C#中的值和引用吗?(上)
  9. 网络通信应用开发利器!—— ESPlus —— ESFramework通信框架的增强库
  10. TypeError: 'module' object is not callable 原因分析