科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道用IDisposable接口释放.NET资源

用IDisposable接口释放.NET资源

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

通过使用Dispose模式可以适当地释放非内存资源,比如数据库连接、Win32 interop组件和操作系统的句柄。

作者:ghost 来源:CSDN 2007年9月28日

关键字: ghost IDisposable 接口

  • 评论
  • 分享微博
  • 分享邮件
使用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++程序不同的地方。



Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1628159

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章