`
lianxiangbus
  • 浏览: 523751 次
文章分类
社区版块
存档分类
最新评论

用IDisposable接口释放.NET资源

 
阅读更多
使用Dispose 模式能够适当地释放资源,但会增加系统开销。
by Mickey Williams

通过使用Dispose模式可以适当地释放非内存资源,比如数据库连接、Win32 interop组件和操作系统的句柄。你不要指望垃圾收集器能够立即将资源释放掉,因为垃圾收集器是由于管制堆(Managed Heap)的内存紧张时才触发的。你可以快速消耗掉例如数据库连接等少量资源,但会给程序的扩展性造成副面影响。在不必要的时候不能实现Dispose模式,因为它可能会增加系统开销,而这在很多情况下是可以避免的。

在.NET当中Dispose 模式是由一个IDisposable接口来实现的,它包括一个简单的方法--Dispose:

interface IDisposable{ void Dispose();}

最明显的例子是在一个类里当类的实例抢占住一个非管制资源(unmanaged resource)时必须实现IDisposable,比如一个本地数据连接或是操作系统的句柄。

另外,记下一个经常被忽略的应该实现IDisposable接口的例子。当一个类实现IDisposable时,实例的正确用法是当对象不在需要时调用 Dispose方法删除它,因此,在你实现一个类,而该类又包含其他实现IDisposable的类时,必须调用Dispose方法。这通常意味着在该类中你必须实现IDisposable,即使它无法直接处理非管制资源。

以下是一个实现IDisposable接口的典型模式:

public class SlalomRacer: IDisposable
{
bool _disposed = false;

public bool IsDisposed
{
get { return _disposed; }
set { _disposed = value; }
}

~SlalomRacer()
{
InternalDispose(false);
}

public void Dispose()
{
InternalDispose(true);
}

protected void InternalDispose(bool disposing)
{
if(disposing)
{
GC.SuppressFinalize(this);
_managedThing.Dispose();
}
_unmanagedThing.Dispose();
}

[...]
}


在前面的代码片断中,当IDisposable被实现时,可以通过两种方法调用disposal代码。首先,如果你直接调用Dispose方法,所有管制和非管制对象均会被列为被清除目标。可以看到终止操作会执行一个阻止对象被清除掉的优化的步骤。还注意到可以安全地多次调用Dispose方法。调用 dispose方法之后,会使用一个标志来确保这个对象上的任何一个方法都不能被调用,示例代码如下:

public void SeekHotTub()
{
if(IsDisposed)
throw new ObjectDisposedException("BT");
}

ObjectDisposedException会提醒你前面已经使用了一个disposed对象。在一个使用过disposed对象上调用其他方法时引发异常是完全有必要的--毕竟,你不能再次使用这些disposed对象。

其次,如果你不调用这个Dispose方法,终止操作会自己调用Dispose(false),它会采用一个和前段代码稍有不同的代码路径。第一,不清除那些管制对象,即使他们也实现了IDisposable接口。你无法确定对象引用是有效的--这些对象可能在等待操作的终止,或者已经被终止了。第二,也没有必要去调用GC.SuppressFinalization,因为这些对象已被终止使用了。

最后,如果你在使用C#,你应该利用其语言固有的对IDisposable接口的支持来实现对象清除,你可以使用以下声明:

using(SlalomRacer mickey = new SlalomRacer())
{
// use mickey here
mickey.RunGates();
mickey.GetStitches();
}// mickey disposed automatically here

C#编辑器会适当地发出调用Dispose方法的IL代码,即使会引发异常。

IDisposable接口的使用规则如下:

1.如果对象实现了IDisposable接口及其dispose方法,那么托管资源和非托管资源都由dispose来释放,最后不会调用析构函数。

2.如果dispose方法没有被调用,那么CLR就会调用析构函数,释放非托管资源。

以下就是实现IDisposable接口后对象调用的流程图:

问题释疑:

1、IDisposable接口为.net程序提供了资源(托管和非托管)释放的便利工具,加入对象调用程序不显示调用dispose方法,那么托管资源就不会被释放,从而会引发内存泄漏等问题。

2、采用dispose释放托管资源后,并不意味着对象它的生存周期已结束,你仍可以在其他地方引用它,这是于c++程序不同的地方。
分享到:
评论

相关推荐

    。net面试大全(附答案)

    2.对于一个实现了IDisposable接口的类,以下哪些项可以执行与释放或重置非托管资源相关的应用程序定义的任务?(多选) ( ABC ) A.Close B.Dispose C.Finalize D.using E.Quit 3.以下关于ref和out的描述哪些项是...

    .net性能优化宝典

    1.1.3 实现 IDisposable 接口... 4 1.2 String 操作... 5 1.2.1 使用 StringBuilder 做字符串连接... 5 1.2.2 避免不必要的调用 ToUpper 或 ToLower 方法... 5 1.2.3 最快的空串比较方法... 6 1.3 多线程... 6 ...

    ASP.NET开发实战1200例(第Ⅰ卷)第三章

    实例097 实现IDisposable接口释放占有资源 153 实例098 对象比较——对象也能排序 155 实例099 无名英雄——匿名方法 156 实例100 .Net框架自身提供的属性(Attribute) 157 实例101 把类当数组用——使用索引器 159...

    .net非托管资源的回收方法

    2、实现System.IDisposable接口   一、析构函数  构造函数可以指定必须在创建类的实例时进行的某些操作,在垃圾收集器删除对象时,也可以调用析构函数。析构函数初看起来似乎是放置释放未托管资源、执行一般清理...

    ADO.NET编程之基础知识

    一.ADO.NET基础 程序和数据库交互,要通过...实现了IDisposable接口的对象,在使用完了,要进行资源的释放。调用Dispose()方法。 连接方式访问数据库,连接要打开,使用完要关闭。关闭之后,还可以再打开,这就是Cl

    C#与.NET技术平台实战演练.part1

    C#借由回收站回收资源10-11使用Finalize方法Finalize对效率的影响10-12编写析构器使用析构器的考虑10-13实现IDisposable接口第11章继承.多态与接口11-l扩充基础类的功能11-1-l继承的语法11-l-2简单的UML描述11-2扩充...

    简单的ADO.net数据访问客户端

    // 在不用在意资源释放的情况下使用DataReader,利用了foreach的机制,在循环结束后DataReader会自动关闭 IEnumerable<IDataRecord> rows = Db.Northwind.Rows( "SELECT ProductName, SupplierID FROM Products ...

    Redis的.net客户端StackExchange.Redis.zip

     }虽然ConnectionMultiplexer是实现了IDisposable接口的,但是我们基于重用的考虑,一般不需要去释放它。当作内存数据库使用IDatabase db = redis.GetDatabase(); 这里的GetDatabase() 返回的db对象是很轻量...

    Unity MVC3依赖注入示例源码2012518

    项目包含一个定制的DependencyResolver,为每一个HTTP请求创建一个子容器并且在请求结束时释放所有注册过IDisposable接口的实例。 来自51ASpXA library that allows simple Integration of Microsoft's Unity IoC ...

    C#与.NET技术平台实战演练.part2

    C#借由回收站回收资源10-11使用Finalize方法Finalize对效率的影响10-12编写析构器使用析构器的考虑10-13实现IDisposable接口第11章继承.多态与接口11-l扩充基础类的功能11-1-l继承的语法11-l-2简单的UML描述11-2扩充...

    numerousapp-net:适用于众多应用程序的.NET API

    Numerous.NET是 的非官方包装。... 您可以使用using构造或使用.Close()方法释放与客户端关联的资源。 using Numerous.Api;var apiKey = "nmrs_123456789012"; // Replace with your Numerous API keyusin

    C#中标准的IDispose模式代码详解

    .net的GC机制有两个问题:首先GC并不能释放所有资源,它更不能释放非托管资源。其次,GC也不是实时的,所有GC存在不确定性。 为了解决这个问题donet提供了析构函数 public class TestClass : System.IDisposable {...

    C#实训教程

    10.5 释放未托管的资源 195 10.6 析构函数 195 10.7 IDisposable接口 196 10.8 实现IDisposable接口和析构函数 198 10.9 不安全的代码 199 10.10 指针 200 10.11 使用指针优化性能 213 10.12 内容总结 217 ...

Global site tag (gtag.js) - Google Analytics