知识大全 深入.NET托管堆(managedheap)(1)

Posted

篇首语:笛里谁知壮士心,沙头空照征人骨。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 深入.NET托管堆(managedheap)(1)相关的知识,希望对你有一定的参考价值。

深入.NET托管堆(managedheap)(1)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  在 NET的所有技术中 最具争议的恐怕是垃圾收集(Garbage Collection GC)了 作为 NET框架中一个重要的部分 托管堆和垃圾收集机制对我们中的大部分人来说是陌生的概念 在这篇文章中将要讨论托管堆 和你将从中得到怎样的好处

    

    

  为什么要托管堆?

    

   NET框架包含一个托管堆 所有的 NET语言在分配引用类型对象时都要使用它 像值类型这样的轻量级对象始终分配在栈中 但是所有的类实例和数组都被生成在一个内存池中 这个内存池就是托管堆

    

  垃圾收集器的基本算法很简单

    

  ● 将所有的托管内存标记为垃圾

    

  ● 寻找正被使用的内存块 并将他们标记为有效

    

  ● 释放所有没有被使用的内存块

    

  ● 整理堆以减少碎片

  

  托管堆优化

    

  看上去似乎很简单 但是垃圾收集器实际采用的步骤和堆管理系统的其他部分并非微不足道 其中常常涉及为提高性能而作的优化设计 举例来说 垃圾收集遍历整个内存池具有很高的开销 然而 研究表明大部分在托管堆上分配的对象只有很短的生存期 因此堆被分成三个段 称作generations 新分配的对象被放在generation 中 这个generation是最先被回收的——在这个generation中最有可能找到不再使用的内存 由于它的尺寸很小(小到足以放进处理器的L cache中) 因此在它里面的回收将是最快和最高效的

    

  托管堆的另外一种优化操作与locality of reference规则有关 该规则表明 一起分配的对象经常被一起使用 如果对象们在堆中位置很紧凑的话 高速缓存的性能将会得到提高 由于托管堆的天性 对象们总是被分配在连续的地址上 托管堆总是保持紧凑 结果使得对象们始终彼此靠近 永远不会分得很远 这一点与标准堆提供的非托管代码形成了鲜明的对比 在标准堆中 堆很容易变成碎片 而且一起分配的对象经常分得很远

    

  还有一种优化是与大对象有关的 通常 大对象具有很长的生存期 当一个大对象在 NET托管堆中产生时 它被分配在堆的一个特殊部分中 这部分堆永远不会被整理 因为移动大对象所带来的开销超过了整理这部分堆所能提高的性能

    

  关于外部资源(External Resources)的问题

    

  垃圾收集器能够有效地管理从托管堆中释放的资源 但是资源回收操作只有在内存紧张而触发一个回收动作时才执行 那么 类是怎样来管理像数据库连接或者窗口句柄这样有限的资源的呢?等待 直到垃圾回收被触发之后再清理数据库连接或者文件句柄并不是一个好方法 这会严重降低系统的性能

    

  所有拥有外部资源的类 在这些资源已经不再用到的时候 都应当执行Close或者Dispose方法 从Beta (译注 本文中所有的Beta 均是指 NET Framework Beta 不再特别注明)开始 Dispose模式通过IDisposable接口来实现 这将在本文的后续部分讨论

    

  需要清理外部资源的类还应当实现一个终止操作(finalizer) 在C#中 创建终止操作的首选方式是在析构函数中实现 而在Framework层 终止操作的实现则是通过重载System Object Finalize 方法 以下两种实现终止操作的方法是等效的

    

  ~OverdueBookLocator()

    

  

    

  Dispose(false);

    

  

    

  和

    

  public void Finalize()

    

  

    

  base Finalize();

    

  Dispose(false);

    

  

    

  在C#中 同时在Finalize方法和析构函数实现终止操作将会导致错误的产生

    

  除非你有足够的理由 否则你不应该创建析构函数或者Finalize方法 终止操作会降低系统的性能 并且增加执行期的内存开销 同时 由于终止操作被执行的方式 你并不能保证何时一个终止操作会被执行

    

  内存分配和垃圾回收的细节

    

  对GC有了一个总体印象之后 让我们来讨论关于托管堆中的分配与回收工作的细节 托管堆看起来与我们已经熟悉的C++编程中的传统的堆一点都不像 在传统的堆中 数据结构习惯于使用大块的空闲内存 在其中查找特定大小的内存块是一件很耗时的工作 尤其是当内存中充满碎片的时候 与此不同 在托管堆中 内存被组制成连续的数组 指针总是巡著已经被使用的内存和未被使用的内存之间的边界移动 当内存被分配的时候 指针只是简单地递增——由此而来的一个好处是 分配操作的效率得到了很大的提升

    

  当对象被分配的时候 它们一开始被放在generation 中 当generation 的大小快要达到它的上限的时候 一个只在generation 中执行的回收操作被触发 由于generation 的大小很小 因此这将是一个非常快的GC过程 这个GC过程的结果是将generation 彻底的刷新了一遍 不再使用的对象被释放 确实正被使用的对象被整理并移入generation 中

    

  当generation 的大小随着从generation 中移入的对象数量的增加而接近它的上限的时候 一个回收动作被触发来在generation 和generation 中执行GC过程 如同在generation 中一样 不再使用的对象被释放 正在被使用的对象被整理并移入下一个generation中 大部分GC过程的主要目标是generation 因为在generation 中最有可能存在大量的已不再使用的临时对象 对generation 的回收过程具有很高的开销 并且此过程只有在generation 和generation 的GC过程不能释放足够的内存时才会被触发 如果对generation 的GC过程仍然不能释放足够的内存 那么系统就会抛出OutOfMemoryException异常

    

  带有终止操作的对象的垃圾收集过程要稍微复杂一些 当一个带有终止操作的对象被标记为垃圾时 它并不会被立即释放 相反 它会被放置在一个终止队列(finalization queue)中 此队列为这个对象建立一个引用 来避免这个对象被回收 后台线程为队列中的每个对象执行它们各自的终止操作 并且将已经执行过终止操作的对象从终止队列中删除 只有那些已经执行过终止操作的对象才会在下一次垃圾回收过程中被从内存中删除 这样做的一个后果是 等待被终止的对象有可能在它被清除之前 被移入更高一级的generation中 从而增加它被清除的延迟时间

    

  需要执行终止操作的对象应当实现IDisposable接口 以便客户程序通过此接口快速执行终止动作 IDisposable接口包含一个方法——Dispose 这个被Beta 引入的接口 采用一种在Beta 之前就已经被广泛使用的模式实现 从本质上讲 一个需要终止操作的对象暴露出Dispose方法 这个方法被用来释放外部资源并抑制终止操作 就象下面这个程序片断所演示的那样

    

  public class OverdueBookLocator: IDisposable

    

  

    

  ~OverdueBookLocator()

    

  

    

  InternalDispose(false);

    

  

    

    

    

  public void Dispose()

    

  

    

  InternalDispose(true);

    

  

    

  protected void InternalDispose(bool disposing)

    

  

    

  if(disposing)

    

  

    

  GC SuppressFinalize(this);

    

  // Dispose of managed objects if disposing

    

  

    

  // free external resources here

    

  

    

cha138/Article/program/net/201311/12014

相关参考

知识大全 ASP.NET技巧:非托管COM组件的使用

ASP.NET技巧:非托管COM组件的使用  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  众所周

知识大全 .net中非托管资源如何清理

  背景这两天帮助其它项目组Review代码发现有些地方实现了IDispose接口同时也发现了一些关于IDispose的问题:        

知识大全 调用非托管dll常出现的bug及解决办法

  C和C++有很多好的类库的沉淀在NET中完全抛弃它们而重头再来是非常不明智的也是不现实的所以我们经常需要通过Pinvoke来使用以前遗留下来的非托管的dll就NET中使用非托管的dll经验而言经常

知识大全 深入探讨.NET中的钩子技术[1]

深入探讨.NET中的钩子技术[1]  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  一介绍  本文

知识大全 深入ASP.NET数据绑定(上)

深入ASP.NET数据绑定(上)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  在ASPNET我

知识大全 深入探讨.NET中的钩子技术

深入探讨.NET中的钩子技术  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  一介绍 &

知识大全 深入了解ASP.NET运行内幕

深入了解ASP.NET运行内幕  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  事情要知道根本所在

知识大全 深入了解ASP.NET中的“空”

深入了解ASP.NET中的“空”  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  空对于许多开发人

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

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

知识大全 VS.NET安装部署深入研究

VS.NET安装部署深入研究  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  相信很多人都做过安装