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

  在开始本文前,需要一些准备知识。首先要提出“什么是资源”。在CLR出来之后,Windows系统资源开始分为“非托管资源”和“托管资源”。非托管资源是指:所有的Window内核对象(句柄)都是非托管资源,如对于Stream,数据库连接,GDI+的相关对象,还有Com对象等等,这些资源并不是受到CLR管理;托管资源是指:由CLR管理分配和释放的资源,即由CLR里new出来的对象。

  其次再来讲,资源的释放方式。非托管资源:需要显式释放的,也即需要你写代码释放;托管资源:并不需要显式释放,但是如果引用类型本身含有非托管资源,则需要进行现实释放;显式释放的C#实现,由C#语法支持的有:

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

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

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

3:提供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:托管资源本身是否需要显式释放。答案显然是:不需要;

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

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

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

时间: 2024-09-28 02:35:09

C#资源释放及Dispose、Close和析构方法的相关文章

一起谈.NET技术,C#资源释放及Dispose、Close和析构方法

在开始本文前,需要一些准备知识.首先要提出"什么是资源".在CLR出来之后,Windows系统资源开始分为"非托管资源"和"托管资源".非托管资源是指:所有的Window内核对象(句柄)都是非托管资源,如对于Stream,数据库连接,GDI+的相关对象,还有Com对象等等,这些资源并不是受到CLR管理:托管资源是指:由CLR管理分配和释放的资源,即由CLR里new出来的对象. 其次再来讲,资源的释放方式.非托管资源:需要显式释放的,也即需要你写代

C#资源释放及Dispose、“.NET研究”Close和析构方法

在开始本文前,需要一些准备知识.首先要提出"什么是资源".在CLR出来之后,Windows系统资源开始分为"非托管资源"和"托管资源&rdq上海网站建设uo;.非托管资源是指:所有的Window内核对象(句柄)都是非托管资源,如对于Stream,数据库连接,GDI+的相关对象,还有Com对象等等,这些资源并不是受到CLR管理:托管资源是指:由CLR管理分配和释放的资源,即由CLR里new出来的对象. 其次再来讲,资源的释放方式.非托管资源:需要显式

关于webapi中entityframework资源释放的问题

问题描述 关于webapi中entityframework资源释放的问题 由于要用到EF的延迟加载,所以不能在调用结束后立刻释放上下文.之前webform的做法是在页面OnUnload时释放.webapi中似乎没有合适的地方来释放,filter的OnActionExecuted事件也是在序列化返回数据之前,有没有什么事件可以在序列化之后调用的?这样就能很好的释放EF资源了 解决方案 不要随便using或Dispose DbContexthttp://blog.csdn.net/wanmdb/ar

求教关于c#对象资源释放问题

问题描述 求教关于c#对象资源释放问题 实现接口的Dispose()函数可以释放托管资源么?我看见微软的例子可以,可以举一些释放的例子吗? 解决方案 其实托管的资源只有一种,就是内存,其它的资源都是非托管的 解决方案二: Dispose()函数只是一个平常的函数,本质上它和你定义的别的函数名的函数没有什么不同.所以它当然不能释放托管资源. 你可以用gc.collect()来让gc去释放托管资源. 解决方案三: 如楼上所说,调用gc

关于SocketAsyncEventArgs资源释放的问题

问题描述 最近写个网络程序用到SocketAsyncEventArgs类,参考网上资料初步完成,可是测试时发现内存大量增加,资源释放不掉.每次有一个socket接入后,内存增加,然后断开socket程序内存也在增加.我是当一个socket断开,调用下面函数publicvoidDispose(){try{this.connection.Shutdown(SocketShutdown.Send);}catch(Exception){//Throwifclienthasclosed,soitisnot

IOCP中的socket错误和资源释放处理方法

错误处理和socket释放, 是IOCP编程中的一大难点. 本文试图就IOCP设计中经常遇到的这个难题展开论述并寻找其解决方案, 事实上, 文中所述的解决方式不仅仅适用于IOCP, 它同样适用于EPOLL等多种服务器编程的网络模型中, 前提是: 领会这种处理方式的实质. 正文: 在使用IOCP开发时, 大家经常遇到的一个难题是与socket相关的缓冲区释放不当带来的错误, 这种错误通常是由于多次对同一个指针执行了delete操作引起的. 比如, 当在执行wsasend或wsarecv返回了非pe

php学习笔记 面向对象的构造与析构方法

复制代码 代码如下: <?php /* * 1.对象中成员的访问(在一个对象的内部方法中,去访问本对轩昂中的其他方法和成员属性) * 2.在对象中的方法中都默认有一个$this关键字,这个关键字代表调用这个方法的对象 * * 构造方法 * * 1.是对象创建完成后,"第一个""自动调用"的方法 * * 2.构造方法的定义,方法名是一个固定的, * 在php4中:和类名相同的方法就是构造方法 * 在php5中:构造方法选择使用 魔术方法__construct()

php类的析构方法

析构方法主要是用于释放资源,比如释放数据库连接或者图片资源,或者销毁某个对象. 1.析构方法会被自动调用 2.析构方法主要是用于释放资源 3.析构方法调用顺序是:先创建的对象,后被销毁. 4.析构方法什么时候被调用? 1)当程序退出时 2)当一个对象成为垃圾对象时,该对象的析构方法也会被调用. 当一个对象没有任何引用指向它时,就会成为垃圾对象,php将启用垃圾回收器将其销毁. 格式: function __destruct() { //释放资源的操作} 例: <?php class Person

php学习笔记 面向对象的构造与析构方法_php基础

复制代码 代码如下: <?php /* * 1.对象中成员的访问(在一个对象的内部方法中,去访问本对轩昂中的其他方法和成员属性) * 2.在对象中的方法中都默认有一个$this关键字,这个关键字代表调用这个方法的对象 * * 构造方法 * * 1.是对象创建完成后,"第一个""自动调用"的方法 * * 2.构造方法的定义,方法名是一个固定的, * 在php4中:和类名相同的方法就是构造方法 * 在php5中:构造方法选择使用 魔术方法__construct()