C#或者说.NET的自动内存管理 学习中碰到的问题。

原创 2006年06月01日 15:20:00

    最近在看MSDN2005,准备从VB6.0迁移到C#,由于初学,就从基本的开始。学到公共语言运行库的“自动内存管理”章节时,有几个问题不明白。

MSDN中介绍:

级别和性能

为了优化垃圾回收器的性能,托管堆分为三个生成级别:0、1 和 2。运行时的垃圾回收算法基于以下几个普遍原理,这些垃圾回收方案的原理已在计算机软件业通过实验得到了证实。首先,压缩托管堆的一部分内存要比压缩整个托管堆速度快。其次,较新的对象生存期较短,而较旧的对象生存期则较长。最后,较新的对象趋向于相互关联,并且大致同时由应用程序访问。

运行时的垃圾回收器将新对象存储在第 0 级托管堆中。在应用程序生存期的早期创建的对象如果未被回收,则被升级并存储在第 1 级和第 2 级托管堆中。对象升级的过程将在本主题的后面介绍。因为压缩托管堆的一部分要比压缩整个托管堆速度快,所以此方案允许垃圾回收器在每次执行回收时释放特定级别的内存,而不是整个托管堆的内存。

实际上,垃圾回收器在第 0 级托管堆已满时执行回收。如果应用程序在第 0 级托管堆已满时尝试新建对象,垃圾回收器将会发现第 0 级托管堆中没有可分配给该对象的剩余地址空间。垃圾回收器执行回收,尝试为对象释放第 0 级托管堆中的地址空间。垃圾回收器从检查第 0 级托管堆中的对象(而不是托管堆中的所有对象)开始执行回收。这是最有效的途径,因为新对象的生存期往往较短,并且期望在执行回收时,应用程序不再使用第 0 级托管堆中的许多对象。另外,单独回收第 0 级托管堆通常可以回收足够的内存,这样,应用程序便可以继续创建新对象。

垃圾回收器执行第 0 级托管堆的回收后,会压缩可访问对象的内存,如本主题前面的释放内存中所述。然后,垃圾回收器升级这些对象,并考虑第 1 级托管堆的这一部分。因为未被回收的对象往往具有较长的生存期,所以将它们升级至更高的级别很有意义。因此,垃圾回收器在每次执行第 0 级托管堆的回收时,不必重新检查第 1 级和第 2 级托管堆中的对象。

在执行第 0 级托管堆的首次回收并把可访问的对象升级至第 1 级托管堆后,垃圾回收器将考虑第 0 级托管堆的其余部分。它将继续为第 0 级托管堆中的新对象分配内存,直至第 0 级托管堆已满并需执行另一回收为止。这时,垃圾回收器的优化引擎会决定是否需要检查较旧的级别中的对象。例如,如果第 0 级托管堆的回收没有回收足够的内存,不能使应用程序成功完成创建新对象的尝试,垃圾回收器就会先执行第 1 级托管堆的回收,然后再执行第 0 级托管堆的回收。如果这样仍不能回收足够的内存,垃圾回收器将执行第 2、1 和 0 级托管堆的回收。每次回收后,垃圾回收器都会压缩第 0 级托管堆中的可访问对象并将它们升级至第 1 级托管堆。第 1 级托管堆中未被回收的对象将会升级至第 2 级托管堆。由于垃圾回收器只支持三个级别,因此第 2 级托管堆中未被回收的对象会继续保留在第 2 级托管堆中,直到在将来的回收中确定它们为无法访问为止。

从网上找来的相关资料:

(三).NET框架垃圾回收机制

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

   .NET框架中的垃圾回收器被称为分代的垃圾回收器(Generational Garbage Collector),也就是说被分配的对象划分为3个类别,或称为“代”。分别为012012代对应的托管堆的初始化大小分别是256K2M10M。垃圾回收器在发现改变大小能够提高性能的话,会改变托管堆的大小。例如当应用程序初始化了许多小的对象,并且这些对象会被很快回收的话,垃圾回收器就会将第0代的托管堆变为128K,并且提高回收的频率。如果情况相反,垃圾回收器发现在第0代的托管堆中不能回收很多空间时,就会增加托管堆的大小。在应用程序初始化的之前,所有等级的托管堆都是空的。当对象被初始化的时候,他们会按照初始化的先后顺序被放入第0代的托管堆中。 

    最近被分配内存空间的对象被放置于第0代,因为第0代很小,小到足以放进处理器的二级(L2)缓存,所以第0代能够为我们提供对其中对象的快速存取。经过一轮垃圾回收后,仍然保留在第0代中的对象被移进第1代中,再经过一轮垃圾内存回收后,仍然保留在第1代中的对象则被移进第2代中。第2代包含了生存期较长的对象,这些对象至少经过了两轮回收。

    C#程序为一个对象分配内存时,托管堆几乎可以立即返回新对象所需的内存,托管堆之所以能有这样高效的内存分配性能是由于托管堆较为简单的数据结构。托管堆类似于简单的字节数组,有一个指向第一个可用内存空间的指针。

    在某块被某对象所请求时,上述指针值就会返回给调用函数,而指针会重新调整至指向下一个可用的内存空间。分配一个托管内存块只比递增一个指针的值稍微复杂一点。这也是托管堆所优化的性能之一。在一个不需太多垃圾回收的应用程序中,托管堆的表现会优于传统的堆。

    由于这个线性的内存分配方法的存在,在C#应用程序中同时分配的对象在托管堆上通常会被分配成彼此相邻。着安排和传统的堆内存分配完全不同,传统的堆内存分配是基于内存块大小的。例如,两个同时分配的对象在堆上的位置可能相距很远,从而降低了缓存的性能。因此虽然内存分配很快,但在一些比较重要的程序中,第0代中的可用内存很有可能会彻底被消耗光。记住,第0代小到可以装进L2缓冲区,并且没有被使用的内存不会被自动释放。当第0代中没有可以分配的有效内存时,就会在第0代中触发一轮垃圾回收,在这轮垃圾回收中将删除所有不再被引用的对象,并将当前正在使用中的对象移至第1代。针对第0代的垃圾回收是最常见的回收类型,而且速度很快。在第0代的垃圾内存回收不能有效的请求到充足的内存时,就启动第1代的垃圾内存回收。第2代的垃圾内存回收要作为最后一种手段而使用,当且仅当第1代和第0代的垃圾内存回收不能被提供足够内存时进行。如果各代都进行了垃圾回收后仍没有可用的内存,就会引发一个OutOfMemeryException异常 。

      按照上面两篇资料的说明,我的理解为:第一次对0级托管堆执行回收后,原先0级托管堆中可访问的对象都升级至第 1 级托管堆,此时0级托管堆的可利用大小应该是原始大小。重复执行数次0级托管堆的回收后,如果1级托管堆已满,0级托管堆中的可访问对象无法升级到1级托管堆中。此时,看0级托管堆中的可利用大小是否能满足新对象的要求,如果可满足,则在0级托管堆中创建新对象;如果无法满足,则对1级托管堆进行回收,并将1级托管堆的可访问对象升级到2级托管堆,同时将0级托管堆中的可访问对象升级到1级托管堆中,这样0级托管堆就清空了,可以满足创建新对象的需要。如此重复执行回收到2级托管堆满,同时1级托管堆也空间放下0级托管堆必须升级的可访问对象,则执行2级托管堆的回收,再执行1级托管堆的回收,然后执行0级托管堆的回收,最后在0级托管堆中创建新对象。

     不知道这样的理解是否正确?!

C#的自动内存管理机制-ASP.NET中的垃圾回收机制(GC)【资料来自网络】

ASP.NET中的垃圾回收机制(GC)【资料来自网络】 ASP.NET中的垃圾回收机制: 在说这个问题的时候,我们先引入一个在GC中比较常见的内容,那就是--托管资源,那么什么是托管资源呢?其...

学习Object-C的碰到的一些问题或者说面试题

1、Objective-C的类可以多重继承么?可以采用多个协议么?          答:不可以多重继承,可以采用多个协议。 2、#import和#include的区别是什么?#import  ...

在ASP.NET中使用IHttpHandler处理请求(如自实现AJAX)时,无法获得Session(或者说是Session 为 null)的原因及解决方法

本文以CSDN以前的一个帖子为线索,结合自己的使用经历,讨论了“使用IHttpHandler得到Session时总是为null”的原因,并给出了解决的方法。...
  • lslxdx
  • lslxdx
  • 2011年04月07日 20:32
  • 1094

垃圾回收GC:.Net自动内存管理 上(三)终结器

GC提供了另外一个能够给你带来好处的功能:终结器。在一个资源被回收后,终结器允许一个优雅的清理操作。使用终结器,当GC释放资源所占的内存时,它们可以进行适当的自我清理。表面上,终结器看起来直接了当:你...

垃圾回收GC:.Net自动内存管理 上(一)内存分配

.NET CLR将所有资源分配到托管堆上,这有点像C语言中的堆但是你不用去释放资源因为闲置资源在.NET中将被自动释放。现在就有一个问题了,托管堆是怎么知道一个对象什么时候将不再被程序使用?现今有很多...

《Effective C#》读书笔记——了解.NET内存管理机制<.NET资源管理>

我们知道C#是一门虚拟机语言,在C#编译器首先将C#代码编译成IL代码,运行程序时CLR(Common Language Runtime,公共语言运行时)通过调用JIT(just-in-time Co...

.net 内存管理

  • 2015年12月26日 10:54
  • 6.65MB
  • 下载

.net重点知识复习(内存管理、垃圾回收、反射)

垃圾回收机制 反射机制

.Net内存管理机制详解

以前对.net 的内存机制有点了解,但了解的不是特别详细。看到一篇博客,顿时明白很多。   引言 作为一个.NET程序员,我们知道托管代码的内存管理是自动的。.NET可以保证我们的托管程序在...
  • fhzh520
  • fhzh520
  • 2012年08月09日 15:14
  • 1665

.NET的GC内存管理与GC回收机制

摘要:今天我们漫谈C#中的垃圾回收机制,本文将从垃圾回收机制的原理讲起,希望对大家有所帮助。   GC的前世与今生   虽然本文是以.NET作为目标来讲述GC,但是GC的概念并非才诞生...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C#或者说.NET的自动内存管理 学习中碰到的问题。
举报原因:
原因补充:

(最多只允许输入30个字)