• Dispose

类型的 Dispose 方法应释放它拥有的所有资源。它还应该通过调用其父类型的 Dispose 方法释放其基类型拥有的所有资源。该父类型的 Dispose 方法应该释放它拥有的所有资源并同样也调用其父类型的 Dispose 方法,从而在整个基类型层次结构中传播此模式。若要确保始终正确地清理资源,Dispose 方法应该可以被多次调用而不引发任何异常。Dispose 方法应该为它处置的对象调用 GC.SuppressFinalize 方法。如果对象当前在终止队列中,GC.SuppressFinalize 防止其 Finalize 方法被调用。请记住,执行 Finalize 方法会大大减损性能。如果您的 Dispose 方法已经完成了清理对象的工作,那么垃圾回收器就不必再调用对象的 Finalize 方法。

    • 设计原则
     应用程序或类库应只允许一个线程拥有资源的生存期,并且应在不再需要资源时调用 Dispose。根据资源的不同,在处置资源时进行异步线程访问可能会带来安全风险。开发人员应仔细检查自己的代码,以确定最佳的方法来强制线程安全。
    • 代码示例
public class BaseResource: IDisposable
{

  // 非托管资源
   private IntPtr handle;

  // 托管资源
   private Component Components;
   // 对象是否已被释放的标志
   private bool disposed = false;

   public BaseResource()   {   }

   // 释放资源,对外开放的可调用的方法
public void Dispose()
{

     // 释放资源
      Dispose(true);

     // 指示在析构函数中跳过垃圾回收
      GC.SuppressFinalize(this);
} // 释放资源,如果disposing为true,释放所有的托管资源和非托管资源,如果为false,则仅仅释放非托管资源,这主要是为了避免在析构函数中重复2次进行垃圾回收
protected virtual void Dispose(bool disposing)
{
// 检查该对象是否已经被释放了
if(!this.disposed)
{
if(disposing)
{

           // 释放托管资源
            Components.Dispose();
}

        // 释放非托管资源
         CloseHandle(handle);
handle = IntPtr.Zero;
}

     // 标记该对象为已被释放的对象
      disposed = true;
} // 析构函数,又名终结器
~BaseResource()
{
// 释放非托管资源,在调用终结器方法时系统自动会对托管的资源进行垃圾回收
Dispose(false);
} // 允许多次调用Dispose,但会抛出异常publicvoid DoSomething()
{
if(this.disposed)
{
thrownew ObjectDisposedException();
}
}
}
    • 实现 Close 方法
     对于类型来说,若调用 Close 方法比调用 Dispose 方法更容易,则可以向基类型添加一个公共 Close 方法。Close 方法又会调用没有参数的 Dispose 方法,该方法可以执行正确的清理操作。在基础类库中的所有类的Close方法都是基于该原理构造的。
public void Close()
{
// 释放资源
Dispose();
}
  • Finalize(终结器)
     对于您的应用程序创建的大多数对象,可以依靠 .NET Framework 的垃圾回收器隐式地执行所有必要的内存管理任务。但是,在您创建封装非托管资源的对象时,当您在应用程序中使用完这些非托管资源之后,您必须显式地释放它们。
     虽然垃圾回收器可以跟踪封装非托管资源的对象的生存期,但它不了解具体如何清理这些资源。对于这些类型的对象,.NET Framework 提供 Object.Finalize 方法,它允许对象在垃圾回收器回收该对象使用的内存时适当清理其非托管资源。但是对托管对象就不应该实现 Finalize方法,因为垃圾回收器会自动清理托管资源。
     默认情况下,Finalize 方法不执行任何操作。如果您要让垃圾回收器在回收对象的内存之前对对象执行清理操作,您必须在类中重写 Finalize 方法。但是在 C# 或 C++ 编程语言中无法重写 Finalize 方法,所以在 C# 中可使用析构函数语法实现 Finalize 方法。
     Finalize 方法主要是在未能调用 Dispose 方法的情况下充当防护措施来清理资源。
     实现 Finalize 方法或析构函数对性能可能会有负面影响,因此应避免不必要地使用它们。
     用 Finalize 方法回收对象使用的内存需要至少两次垃圾回收。当垃圾回收器执行回收时,它只回收没有终结器的不可访问对象的内存。这时,它不能回收具有终结器的不可访问对象。它改为将这些对象的项从终止队列中移除并将它们放置在标为准备终止的对象列表中。该列表中的项指向托管堆中准备被调用其终止代码的对象。垃圾回收器为此列表中的对象调用 Finalize 方法,然后,将这些项从列表中移除。后来的垃圾回收将确定终止的对象确实是垃圾,因为标为准备终止对象的列表中的项不再指向它们。在后来的垃圾回收中,实际上回收了对象的内存。
  • 封装资源对象
     如果您要编写代码,而该代码使用一个封装资源的对象,您应该确保在使用完该对象时调用该对象的 Dispose 方法。
    • 封装方式
      • using语句
      • try/finally块

.NET 清理非托管资源的更多相关文章

  1. .NET垃圾回收:非托管资源,IDispose和析构函数的结合

    http://blog.jobbole.com/85436/ 原文出处: 田小计划   欢迎分享原创到伯乐头条 前面一篇文章介绍了垃圾回收的基本工作原理,垃圾回收器并不是可以管理内存中的所有资源.对于 ...

  2. C# using 三种使用方式 C#中托管与非托管 C#托管资源和非托管资源区别

    1.using指令.using + 命名空间名字,这样可以在程序中直接用命令空间中的类型,而不必指定类型的详细命名空间,类似于Java的import,这个功能也是最常用的,几乎每个cs的程序都会用到. ...

  3. .NET垃圾回收 – 非托管资源

    前面一篇文章介绍了垃圾回收的基本工作原理,垃圾回收器并不是可以管理内存中的所有资源.对于所有的托管资源都将有.NET垃圾回收机制来释放,但是,对于一些非托管资源,我们就需要自己编写代码来清理这类资源了 ...

  4. C# 释放非托管资源

    C#中资源分为托管资源和非托管资源. 托管资源由垃圾回收器控制如何释放,不需要程序员过多的考虑(当然也程序员也可以自己释放). 非托管资源需要自己编写代码来释放.那么编写好的释放非托管资源的代码(释非 ...

  5. .net 资源释放(托管资源和非托管资源)

    1.托管资源 像int.float.DateTime等都是托管资源:net中80%的资源都是托管资源: 托管资源的回收通过GC(垃圾回收器)自动释放分配给该对象的内存,但无法预测进行垃圾回收的时间,我 ...

  6. 6.C# 释放非托管资源2

    C# 释放非托管资源 C#中资源分为托管资源和非托管资源. 托管资源由垃圾回收器控制如何释放,不需要程序员过多的考虑(当然也程序员也可以自己释放). 非托管资源需要自己编写代码来释放.那么编写好的释放 ...

  7. C# 托管资源和非托管资源

    托管资源指的是.NET可以自动进行回收的资源,主要是指托管堆上分配的内存资源.托管资源的回收工作是不需要人工干预的,有.NET运行库在合适调用垃圾回收器进行回收. 非托管资源指的是.NET不知道如何回 ...

  8. C#处理非托管资源

    using System; //处理非托管资源 //例如:文件句柄.网络连接.数据库连接 //实现IDisposable不意味着也应该实现一个终结器,终结器会带来额外开销 //发布本机资源,要释放本机 ...

  9. 5.C#释放非托管资源1

    释放非托管资源 在介绍释放非托管资源的时候,我觉得有必要先来认识一下啥叫非托管资源,既然有非托管资源,肯定有托管资源. 托管资源指的是.net可以自棕进行回收的资源,主要是指托管堆上分配的内存资源.托 ...

随机推荐

  1. AppBox升级进行时 - Entity Framework的增删改查

    AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理.职称管理.部门管理.角色管理.角色权限管理等模块. Entity Framework新增数据 以新增用户为例,作为对比,先来看下使 ...

  2. java/python中的队列

    Queue<TreeNode> que=new LinkedList<>(); 用linkedlist实现队列,offer,poll进出队列,peek对列顶部元素 python ...

  3. VS使用技巧——统计代码行数

    通常为了统计一个文件或者一整个解决管理方案中代码行量,可能会选择定位来获取行量,但是当文件尤其大时,传统方式就不行了,这里推荐使用正则表达式搜索统计,可以快速获取目标文档的总代码量. Tips: ct ...

  4. JQUERY 测验

    1.下面哪种说法是正确的? 您的回答:jQuery 是 JSON 库 正确答案:jQuery 是 JavaScript 库 2.jQuery 使用 CSS 选择器来选取元素? 您的回答:错误 正确答案 ...

  5. MongoDB系列二

    简介 MongoDB是一个基于分布式文件存储的数据库.由C++语言编写.旨在为WEB应用提供可扩展的高性能数据存储解决方案.  MongoDB是一个高性能,开源,无模式的文档型数据库,是当前NoSql ...

  6. CocoaPods 升级

    也不知道是什么时候,ruby.taobao开始不能用了,在公司的电脑上一直装不上,还卡在那里, 旁边的老大投来了异样的目光,或者我是应该提升下技术了-- 一.升级gem gem update --sy ...

  7. php判断str是否是xml格式

    function xml_parser($str){ $xml_parser = xml_parser_create(); if(!xml_parse($xml_parser,$str,true)){ ...

  8. ThinkPHP3.2.3整合smarty模板(一)

    一.php模板引擎有哪些? 1.1 PHPLIB:一套古老且主流的模板引擎,直接在html中使用PHP变量进行编程: 1.2 Template Blocks:一款轻巧且速度非常快的PHP模板引擎,支持 ...

  9. Tomcat端口被占用错误

    所报错误: 严重: Error initializing endpointjava.lang.Exception: Socket bind failed: [730013] ????????????? ...

  10. 前端开发者进阶之函数柯里化Currying

    穆乙:http://www.cnblogs.com/pigtail/p/3447660.html 在计算机科学中,柯里化(英语:Currying),又译为卡瑞化或加里化,是把接受多个参数的函数变换成接 ...