知识大全 自动内存管理机制深入剖析-C#分析篇

Posted 资源

篇首语:一个不想蹚过小河的人,自然不想远涉重洋。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 自动内存管理机制深入剖析-C#分析篇相关的知识,希望对你有一定的参考价值。

自动内存管理机制深入剖析-C#分析篇  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  在 NET Framework中 内存中的资源(即所有二进制信息的集合)分为 托管资源 和 非托管资源 托管资源必须接受 NET Framework的CLR(通用语言运行时)的管理(诸如内存类型安全性检查) 而非托管资源则不必接受 NET Framework的CLR管理   (了解更多区别请参阅 NET Framework或C#的高级编程资料)

    

  托管资源在 NET Framework中又分别存放在两种地方: 堆栈 和 托管堆 (以下简称 堆 );规则是 所有的值类型(包括引用和对象实例)和引用类型的引用都存放在 堆栈 中 而所有引用所代表的对象实例都保存在堆中

    

  在C#中 释放托管资源是可以自动通过 垃圾回收器 完成的(注意 垃圾回收 机制是 NET Framework的特性 而不是C#的) 但具体来说 仍有些需要注意的地方:

    

   值类型(包括引用和对象实例)和引用类型的引用其实是不需要什么 垃圾回收器 来释放内存的 因为当它们出了作用域后会自动释放所占内存(因为它们都保存在 堆栈 中 学过数据结构可知这是一种先进后出的结构);

    

   只有引用类型的引用所指向的对象实例才保存在 堆 中 而堆因为是一个自由存储空间 所以它并没有像 堆栈 那样有生存期( 堆栈 的元素弹出后就代表生存期结束 也就代表释放了内存) 并且非常要注意的是 垃圾回收器 只对这块区域起作用;

    

   垃圾回收器 也许并不像许多人想象的一样会立即执行(当堆中的资源需要释放时) 而是在引用类型的引用被删除和它在 堆 中的对象实例被删除中间有个间隔 为什么呢? 因为 垃圾回收器 的调用是比较消耗系统资源的 因此不可能经常被调用!

    

  (当然 用户代码可以用方法System GC Collect()来强制执行 垃圾回收器 )

    

  然而 大多数情况下 我们需要明确地在不执行 垃圾回收器 的情况下释放托管资源(因为只需要释放一部分但又是非常需要释放的资源 但最好不要调用 垃圾回收器 因为 垃圾回收器 太浪费系统资源了) 或需要释放 非托管资源 这时候我们该怎么办? 这是我们写代码的时候必须要考虑的问题( 垃圾回收器 是系统自动实现的 一般情况不需要用户干预) 否则Windows系统会因为内存耗尽而

    

  现在 我来告诉怎么办 那就是使用类的Dispose()方法释放所有类型资源 和 使用析构方法释放非托管资源!

    

   Dispose()方法

    

  要通过Dispose()方法来释放资源 那么在类定义的时候执 System IDisposable 接口 然后在类中必须包含这样定义的方法 void Dispose() (在Dispose()方法中就是用户自己写的释放资源的代码段) 这样一来 用户就会知道可以通过人为地调用Dispose()方法来释放资源 不过需要注意的是 垃圾回收器 并不是通过调用Dispose()方法来释放托管资源的!

    

   析构方法

    

  在C#中定义析构方法的格式是 ~CLASS_NAME() 非常需要注意的是 如果一个类中没有使用到非托管资源 那么请一定不要定义析构方法 这是因为对象执行了析构方法 那么 垃圾回收器 在释放托管资源之前要先调用析构方法 然后第二次才真正释放托管资源 这样一来 两次删除动作的花销比一次大多的! (不过 即使你在类中已经定义了析构方法 仍然有办法 屏蔽 它 这将在后面的代码范例中说明) 在析构方法中 就是用户自己写的释放非托管资源的代码段

    

  下面使用一段代码来示范Dispose()方法和析构方法如何使用:

    

  public class ResourceHolder : System IDisposable

  

  public void Dispose()

  

  Dispose(true);

  System GC SuppressFinalize(this);

  // 上面一行代码作用是防止 垃圾回收器 调用这个类中的方法

  // ~ResourceHolder()

  // 为什么要防止呢? 因为如果用户记得调用Dispose()方法 那么

  // 垃圾回收器 就没有必要 多此一举 地再去释放一遍 非托管资源 了

  // 如果用户不记得调用呢 就让 垃圾回收器 帮我们去 多此一举 吧 ^_^

  // 你看不懂我上面说的不要紧 下面我还有更详细的解释呢!

    

  

    

  protected virtual void Dispose(bool disposing)

  

  if (disposing)

  

  // 这里是清理 托管资源 的用户代码段

  

  // 这里是清理 非托管资源 的用户代码段

  

    

  ~ResourceHolder()

  

  Dispose(false);

  

  

    

  上面的代码是一个典型的有两种Dispose方法的类定义

    

  在 NET Framework中有很多系统类是用这种方法定义Dispose()方法的 例如:

    

  MSDN中 System Drawing Brush Dispose方法就是这样定义的:

    

  ************************************************************

  * 释放由此 Brush 对象使用的所有资源                       *

  * public void Dispose()                                    *

  * 该成员支持 NET 框架结构 因此不适用于直接从代码中使用 *

  * protected virtual void Dispose(bool);                    *

  ************************************************************

    

  这里 我们必须要清楚 需要用户调用的是方法Dispose()而不是方法Dispose(bool) 然而 这里真正执行释放工作的方法却并不是Dispose() 而是Dispose(bool) ! 为什么呢?仔细看代码 在Dispose()中 调用了Dispose(true) 而参数为 true 时 作用是清理所有的托管资源和非托管资源;大家一定还记得我前面才说过 使用析构方法是用来释放非托管资源的 那么这里既然Dispose()可以完成释放非托管资源的工作 还要析构方法干什么呢? 其实 析构方法的作用仅仅是一个 备份 !

  

  为什么呢?

    

  严格地说 凡执行了接口 IDisposable 的类 那么只要程序员在代码中使用了这个类的对象实例 那么早晚得调用这个类的Dispose()方法 同时 如果类中含有对非托管资源的使用 那么也必须释放非托管资源! 可惜 如果释放非托管资源的代码放在析构方法中(上面的例子对应的是 ~ResourceHolder() ) 那么程序员想调用这段释放代码是不可能做到的(因为析构方法不能被用户调用 只能被系统 确切说是 垃圾回收器 调用) 所以大家应该知道为什么上面例子中 清理非托管资源的用户代码段 是在Dispose(bool)中 而不是~ResourceHolder()中! 不过不幸的是 并不是所有的程序员都时刻小心地记得调用Dispose()方法 万一程序员忘记调用此方法 托管资源当然没问题 早晚会有 垃圾回收器 来回收(只不过会推迟一会儿) 那么非托管资源呢?它可不受CLR的控制啊!难道它所占用的非托管资源就永远不能释放了吗? 当然不是!我们还有 析构方法 呢! 如果忘记调用Dispose() 那么 垃圾回收器 也会调用 析构方法 来释放非托管资源的!(多说一句废话 如果程序员记得调用Dispose()的话 那么代码 System GC SuppressFinalize(this); 则可以防止 垃圾回收器 调用析构方法 这样就不必多释放一次 非托管资源 了) 所以我们就不怕程序员忘记调用Dispose()方法了

    

  所以我说了这么一大堆的理由 综合起来只有两点:

    

  * 程序员们啊 千万不要忘记调用Dispose()方法! (如果有的话 ^_^)

    

cha138/Article/program/net/201311/12172

相关参考

知识大全 VS2005数据存取层深入剖析高级篇

VS2005数据存取层深入剖析高级篇  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!一扩展表格适配器

知识大全 详解JVM的内存管理机制

详解JVM的内存管理机制  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!我们在深入Java核心系列文

知识大全 PGA自动管理原理深入分析及性能调整

PGA自动管理原理深入分析及性能调整  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! PG

知识大全 面试问题深入剖析(4)

10.你和同事们怎样相处?分析通过这个问题以及前面上下级关系和朋友关系的问题,面试人可以对求职者的有效沟通技能得出一个总体印象。从某种意义上说,如何和同事们相处是最关键的沟通问题,因为根据美国劳工部的

知识大全 面试问题深入剖析(2)

4.你曾经参加过哪些竞争活动?这些活动值得吗?分析通过调查你经历过的实际竞争场景,可以反映出你对竞争环境的适应程度,也可以反映你的自信心。当竞争成为关键因素时,正是讨论小组活动或企业业务的一个绝好机会

知识大全 面试问题深入剖析(3)

7.在写专业论文时你最不喜欢哪些方面?分析这个问题可以判断你是否愿意开展研究工作,是否愿意发现信息并找到困难问题的解决办法。错误回答我最担心的就是进行一个自己不感兴趣的研究课题。如果我对研究课题感兴趣

知识大全 面试问题深入剖析(1)

1.你为什么觉得自己能够在这个职位上取得成就?分析这是一个相当宽泛的问题,它给求职者提供了一个机会,可以让求职者表明自己的热情和挑战欲。对这个问题的回答将为面试人在判断求职者是否对这个职位有足够的动力

知识大全 浅析.NET框架下的自动内存管理

浅析.NET框架下的自动内存管理  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  一抽象类  抽象

知识大全 Oracle数据块原理深入剖析

Oracle数据块原理深入剖析  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  数据块(Oracl

知识大全 深入剖析Asp.net资源文件

深入剖析Asp.net资源文件  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  一资源文件的定义