• C#如何释放未托管资源


    在C#里面有2种机制来释放未托管资源:

    • 声明一个析构函数(或终结器),作为类的一个成员
    • 在类中执行System.IDisposable接口

    析构函数

    下面这段代码是一段带有析构函数的简单代码:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text; 
    
    namespace MemRelease
    {
        class Program
        {
            ~Program()
            {
                // Orders.
            } 
    
            static void Main(string[] args)
            {
            }
        }
    } 
    

    在IL DASM中,你会发现并没有这个析构的方法。C#编译器在编译析构函数时,会隐式地把析构函数的代码编译为Finalize()方法的对应代码,确保执行父类的Finalize()方法 看下这段代码中对于析构函数的编译:

    .method family hidebysig virtual instance void 
            Finalize() cil managed
    {
      // Code size       14 (0xe)
      .maxstack  1
      .try
      {
        IL_0000:  nop
        IL_0001:  nop
        IL_0002:  leave.s    IL_000c
      }  // end .try
      finally
      {
        IL_0004:  ldarg.0
        IL_0005:  call       instance void [mscorlib]System.Object::Finalize()
        IL_000a:  nop
        IL_000b:  endfinally
      }  // end handler
      IL_000c:  nop
      IL_000d:  ret
    } // end of method Program::Finalize 

    是一个try…finally的结构,

    try
    
    {
    
    // destructor implementation
    
    }
    
    finally
    
    {
    
    base.Finalize();
    
    }
    
    

    ~Program()析构函数中执行的代码封装在Finalize()方法的一个try块中。对父类Finalize()方法的调用放在finally块中,确保该调用的执行。

    使用析构函数来释放资源有几个问题:

    1. 与C++析构函数相比,C#析构函数的问题是他们的不确定性。在删除C++对象时,其析构函数会立即执行,但是由于垃圾收集器的工作方式,无法确定C#对象的析构函数何时执行。
    2. C#析构函数的执行会延迟对象最终从内存中删除的时间。有析构函数的对象需要2次处理才能删除:第一次调用析构函数时,没有删除对象,第二次调用才真正删除对象。


    IDisposable接口

    在C#中,推荐使用System.IDisposable接口替代析构函数。IDisposable接口定义一个模式,为释放未托管的资源提供了确定的机制,并避免产生析构函数固有的与垃圾函数器相关的问题。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace MemRelease
    {
        class Program : IDisposable
        {
            public void Dispose()
            {
                // implementation
            }        
    
            static void Main(string[] args)
            {
            }
        }
    }
    

    假定有一个类ResourceGobbler,它使用某些外部资源,且执行IDisposable接口。如果要实例化着各类的实例,使用它,然后释放它,就可以使用下面的代码。

    ResourceGobbler theInstance = new ResoucrGobbler();
    
    // do your processing
    
    theInstance.Dispose();

    如果加入异常处理:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace MemRelease
    {
        public class ResourceGobbler : IDisposable
        {
            public void Dispose()
            {
                //implementation
            }
        }
    
        class Program 
        {        
            static void Main(string[] args)
            {
                ResourceGobbler theInstance = null;
    
                try
                {
                    theInstance = new ResourceGobbler();
                    // do your processing
                }
                finally
                {
                    if (theInstance != null)
                    {
                        theInstance.Dispose();
                    } 
                }
            }
        }
    }
    

    即使在处理过程中出现异常,这个版本也可以确保总是在theInstance上调用Dispose(),总能释放有theInstance使用的资源。

    C#提供了一种语法,可以确保执行IDisposal接口的对象的引用超出作用域时,在该对象上自动调用Dispose().

    using (ResourceGobbler theInstance =  new ResourceGobbler());
    {
        // do your processing
    }
    伪python爱好者,正宗测试实践者。
  • 相关阅读:
    喜大普奔,微软Microsoft JDBC Driver For SQL Server已发布到maven中央仓库
    maven jdbc 驱动安装
    SpringIoC和SpringMVC的快速入门
    再见 Spring Boot 1.X ,Spring Boot 2.X 走向舞台中心
    LRU设计
    二叉搜索树转换成双向链表
    快速排序
    二叉搜索树的先序中序后序非递归遍历代码
    EM算法
    模型调优
  • 原文地址:https://www.cnblogs.com/herbert/p/1750194.html
Copyright © 2020-2023  润新知