zoukankan      html  css  js  c++  java
  • IDispose和Finalize的区别和联系

    using System;
    using System.ComponentModel;

    // The following example demonstrates how to use the
    // GC.SuppressFinalize method in a resource class to prevent
    // the clean-up code for the object from being called twice.

    public class DisposeExample
    {
        // A class that implements IDisposable.
        // By implementing IDisposable, you are announcing that
        // instances of this type allocate scarce resources.
        public class MyResource: IDisposable
        {
            // Pointer to an external unmanaged resource.
            private IntPtr handle;
            // Other managed resource this class uses.
            private Component component = new Component();
            // Track whether Dispose has been called.
            private bool disposed = false;

            // The class constructor.
            public MyResource(IntPtr handle)
            {
                this.handle = handle;
            }

            // Implement IDisposable.
            // Do not make this method virtual.
            // A derived class should not be able to override this method.
            public void Dispose()
            {
                Dispose(true);
                // This object will be cleaned up by the Dispose method.
                // Therefore, you should call GC.SupressFinalize to
                // take this object off the finalization queue
                // and prevent finalization code for this object
                // from executing a second time.
                GC.SuppressFinalize(this);//问题2:在“Dispose()”中“GC.SuppressFinalize(this);”是什么意思?
            }

            // Dispose(bool disposing) executes in two distinct scenarios.
            // If disposing equals true, the method has been called directly
            // or indirectly by a user's code. Managed and unmanaged resources
            // can be disposed.
            // If disposing equals false, the method has been called by the
            // runtime from inside the finalizer and you should not reference
            // other objects. Only unmanaged resources can be disposed.
            private void Dispose(bool disposing)
            {
                // Check to see if Dispose has already been called.
                if(!this.disposed)
                {
                    // If disposing equals true, dispose all managed
                    // and unmanaged resources.
                    if(disposing)
                    {
                        // Dispose managed resources.
                        component.Dispose();//问题1:也就是为什么GC垃圾回收机制在回收对象的时候只回收或者释放非托管资源,而不回收托管资源?
                    }
            
                    // Call the appropriate methods to clean up
                    // unmanaged resources here.
                    // If disposing is false,
                    // only the following code is executed.
                    CloseHandle(handle);
                    handle = IntPtr.Zero;           
                }
                disposed = true;        
            }

            // Use interop to call the method necessary 
            // to clean up the unmanaged resource.
            [System.Runtime.InteropServices.DllImport("Kernel32")]
            private extern static Boolean CloseHandle(IntPtr handle);

            // Use C# destructor syntax for finalization code.
            // This destructor will run only if the Dispose method
            // does not get called.
            // It gives your base class the opportunity to finalize.
            // Do not provide destructors in types derived from this class.
            ~MyResource()     
            {
                // Do not re-create Dispose clean-up code here.
                // Calling Dispose(false) is optimal in terms of
                // readability and maintainability.
                Dispose(false);//问题1:为什么在析构函数中调用的是“Dispose(false);”?
            }
        }

        public static void Main()
        {
            // Insert code here to create
            // and use a MyResource object.
        }
    }

    产生了两个问题(代码中红色标注区域):

    问题1:为什么在析构函数中调用的是“Dispose(false);”,也就是为什么GC垃圾回收机制在回收对
    象的时候只回收或者释放非托管资源,而不回收托管资源?
    问题2:在“Dispose()”中“GC.SuppressFinalize(this);”是什么意思?

    上网搜了写资料,终于了解了这种设计的用意和优点:
    参考资料:
    http://baike.baidu.com/view/4471636.htm
    http://www.360doc.com/content/11/0503/18/6075898_114106056.shtml

    解答问题1:
    在.NET的对象中实际上有两个用于释放资源的函数:Dispose和Finalize。Finalize的目的是用于释放非托管的资源,而Dispose是用于释放所有资源,包括托管的和非托管的。
    在这个模式中,通过一个变量“disposing”来区分是客户调用(true)还是GC调用(false)。
    这是因为,Dispose()函数是被其它代码显式调用并要求释放资源的,而Finalize是被GC调用的。
    在GC调用的时候MyResource所引用的其它托管对象(component)可能还不需要被销毁,并且即使
    要销毁,也会由GC来调用。因此在Finalize中只需要释放非托管资源即可。

    解答问题2:
    由于在Dispose()中已经释放了托管和非托管的资源,因此在对象被GC回收时再次调用Finalize是
    没有必要的,所以在Dispose()中调用GC.SuppressFinalize(this)避免重复调用Finalize。

    因此,上面的模式保证了:
    1、 Finalize只释放非托管资源;
    2、 Dispose释放托管和非托管资源;
    3、 重复调用Finalize和Dispose是没有问题的;
    4、 Finalize和Dispose共享相同的资源释放策略,因此他们之间也是没有冲突的。
    在C#中,这个模式需要显式地实现,其中C#的~MyResource()函数代表了Finalize()。

    优点:
    1、如果客户没有调用Dispose(),未能及时释放托管和非托管资源,那么在垃圾回收时,还有机会执
    行Finalize(),释放非托管资源,但是造成了非托管资源的未及时释放的空闲浪费。
    2、如果客户调用了Dispose(),就能及时释放了托管和非托管资源,那么该对象被垃圾回收时,不回
    执行Finalize(),提高了非托管资源的使用效率并提升了系统性能。

    此外还有Close()方法,此方法一般和Open()方法配合来使用,对于数据库连接,一般可以逆向操作,比如打开->关闭,关闭->打开,而对于文件操作,一般是关闭文件,相当于Dispose(),而且有的用户更愿意使用Close()来释放资源,所以出现了一下这种相当于适配器模式的代码:

    public void Close()

    {

    Dispose(();

    }

    最后还要再说一点,据MSDN上说C#不允许类实现Finalize()方法,所以用析构函数来代替。

  • 相关阅读:
    经济危机下,自主创业已成为一种时代潮流?
    曾靖雯(帮别人名字作诗)
    四大内伤造就80后创业高失败率
    如何让创业的路不再崎岖
    叶莉(帮别人名字作诗)
    谁能够在萧条中生存?历史总是惊人相似的(转)
    哪种书最适合创业者阅读
    中西部崛起 关键是要激发普遍的创业热情
    每日英语:Dating in China Is a Largely Commercial Transaction
    每日英语:Poor Chinese Schools Tell Students: Bring Your Own Desks
  • 原文地址:https://www.cnblogs.com/fengye87626/p/2821304.html
Copyright © 2011-2022 走看看