zoukankan      html  css  js  c++  java
  • .net非托管资源

    常见的非托管资源包括数据库链接、文件句柄、网络链接、互斥体、COM对象、套接字、位图和GDI+对象等

    非托管资源的清理,主要有两种方式:Finalize 方法和 Dispose 方法,这两种方法提供了在垃圾收集执行前进行资源清理的方法。Finalize 方式,又称为终止化操作,其大致的原理为:通过对自定义类型实现一个Finalize 方法来释放非托管资源,而终止化操作在对象的内存回收之前通过调用 Finalize方法来释放资源;Dispose 模式,指的是在类中实现 IDisposable 接口,该接口中的Dispose 方法定义了显式释放由对象引用的所有非托管资源。因此,Dispose 方法提供了更加精确的控制方式,在使用上更加的灵活

    在继承链中所有实例将递归调用 base.Finalize 方法,也就是意味调用终结器释放资

    源时,将释放所有的资源,包括父类对象引用的资源。因此,在 C#中,也无需调用或重写Object.Finalize 方法,事实上显示的重写会引发编译时错误,只需实现虚构函数即可。

    {

    重写了Finalize方法的类型对象,其引用类型对象的代龄将被提升,从而带来内存压力。

    l  Finalize方法在某些情况下可能不被执行,例如可能某个终结器被无限期的阻止,则其他终结器得不到调用。因此,应该确保重写的 Finalize方法尽快被执行。

    基于以上原因,应该避免重写 Finalize 方法,而实现 Dispose 模式来完成对非托管资源的清理操作,具体实现见下文描述。

    对于Finalize 方法,有以下规则值得总结:

    C#中无法显示的重写Finalize方法,只能通过析构函数语法形式来实现。

    l  struct中不允许定义析构函数,只有 class中才可以,并且只能有一个。

    l  Finalize方法不能被继承或重载。

    析构函数不能加任何修饰符,不能带参数,也不能被显示调用,唯一的例外是在子类重写时,通过base调用父类Finalize方法,而且这种方式也被隐式封装在析构函数中。

    执行垃圾回收之前系统会自动执行终止化操作。

    l  Finalize方法中,可以实现使得被清理对象复活的机制,不过这种操作相当危险,而且没有什么实际意义,仅作参考,不推荐使用:对于重写了Finalize 方法的类型来说,可以通过GC. SuppressFinalize 来免除终结。对于Finalize 方式来说,存在如下几个弊端,因此一般情况下在自定义类型中应避免重写 Finalize 方法,这些弊端主要包括:

    终止化操作的时间无法控制,执行顺序也不能保证。因此,在资源清理上不够灵活,也可能由于执行顺序的不确定而访问已经执行了清理的对象。

    l  Finalize方法会极大地损伤性能,GC使用一个终止化队列的内部结构来跟踪具有 Finalize方法的对象。当重写了Finalize方法的类型在创建时,要将其指针添加到该终止化队列中,由此对性能产生影响;另外,垃圾回收时调用 Finalize方法将同时清理所有的资源,包括其父类对象的资源,也是影响性能的一个因素。

    }

    {

    在该模式中,公有Dispose方法通过调用重载虚方法 Disposebool disposing)方法来实现,具体的资源清理操作实现于虚方法中。两种策略的区别是:disposing参数为真时,Dispose方法由用户代码调用,可释放托管或者非托管资源;disposing参数为假时,Dispose方法由Finalize调用,并且只能释放非托管资源。

    l  disposed字段,保证了两次调用Dispose方法不会抛出异常,值得推荐。

    派生类中实现Dispose模式,应该重写基类的受保护Dispose方法,并且通过base调用基类的Dispose方法,以确保释放继承链上所有对象的引用资源,在整个继承层次中传播 Dispose模式。

    protected override void Dispose(bool disposing)

    {

        if (!disposed)

        {

            try

            {

                //子类资源清理

                //......

                disposed = true;

            }

            finally

            {

                base.Dispose(disposing);

            }

        }

    }

    另外,基于编程习惯的考虑,一般在实现Dispose方法时,会附加实现一个Close方法来达到同样的资源清理目的,而 Close内部其实也是通过调用Dispose来实现的。    }

        //实现一个处理资源清理的具体方法

        protected virtual void Dispose(bool disposing)

        {

            if (! disposed)

            {

                if (disposing)

                {

                    //清理托管资源

                }

                //清理非托管资源

                if (_handle != IntPtr.Zero)

                {

                    //执行资源清理,在此为关闭对象句柄

                    CloseHandle(_handle);

                    _handle = IntPtr.Zero;

                }          

            }

            disposed = true;             

        }

        public void Close()

        {

            //在内部调用Dispose来实现

            Dispose();

        }

    }

    在上述实现Dispose模式的典型操作中,有几点说明:

    l  Dispose方法中,应该使用 GC. SuppressFinalize防止 GC调用Finalize方法,因为显式调用Dispose显然是较佳选择。

    公有Dispose方法不能实现为虚方法,以禁止在派生类中重写。Dispose模式

    另一种非托管资源的清理方式是Dispose 模式,其原理是定义的类型必须实现 System.IDisposable接口,该接口中定义了一个公有无参的 Dispose 方法,用户可以在该方法中实现对非托管资源的清理操作。在此,我们实现一个典型的Dispose模式:

    class MyDispose : IDisposable

    {

        //定义一个访问外部资源的句柄

        private IntPtr _handle;

        //标记Dispose是否被调用

        private bool disposed = false;

        //实现IDisposable接口

        public void Dispose()

        {

            Dispose(true);

            //阻止GC调用Finalize方法

            GC.SuppressFinalize(this);

    }

  • 相关阅读:
    字符编码与函数
    linux打印彩色字
    企业级docker仓库Harbor部署
    PyPI使用国内源
    CentOS 7.2 升级内核支持 Docker overlay 网络模式
    购物车2
    购物车
    定制 cobbler TITLE 信息
    06.密码错误3次锁定
    05.for循环语句
  • 原文地址:https://www.cnblogs.com/jiebian/p/3409747.html
Copyright © 2011-2022 走看看