Microsoft.Net框架程序设计学习笔记(37):对象的代龄

利用对象代龄提高垃圾收集效率

  代龄是旨在提高垃圾收集器性能的一种机制。一个基于代龄的垃圾收集器有以下几点假设:

  1. 对象越新,其生存期越短。
  2. 对象越老,其生存期越长。
  3. 对托管堆的一部分执行垃圾收集要比对整个托管堆执行垃圾收集速度更快。

  CLR将对象代龄分为0、1、2,共三代,且对每一代的对象所占用内存容量都设定了一个阀值,代龄越大,内存容量阀值也越大。代龄对象所占用内存超出阀值时,将引发垃圾收集。

  在托管堆初始化时,其中不包括任何对象。这时添加到托管堆中的对象被称为第0代对象。当第0代对象所占用内存超过了阀值时,垃圾收集器就必须启动了。经过垃圾收集后存活下来的对象被认为是第1代对象,同时第0代对象暂时空缺。之后又有新对象分配而成为第0代对象。

  经过一段时间,如果第0代对象所占用内存超过阀值,垃圾收集器又被启动,此时垃圾收集器会同时检查第1代对象所占内存是否超出阀值,如果超出,则垃圾收集器不光对第0代对象进行垃圾收集,还会对第1代对象进行垃圾收集;如未超出,则仅对第0代对象进行垃圾收集。此次收集过后,第0代对象的代龄提升为第1代,第1代对象若被执行了垃圾收集,则代龄提升为第2代。

  由此,每次因新分配对象导致第0代对象超出阀值时都会执行垃圾收集。但每次垃圾收集仅对占用内存超出阀值的代龄对象进行收集。这样保证越老的对象执行垃圾收集的机会越少,且经常仅在托管堆中一部分(即超出阀值的代龄对象上)执行垃圾收集,减小了每次垃圾收集的工作量,提升了垃圾收集的效率与性能。

  CLR的垃圾收集器还会从每次执行垃圾收集的结果中学习应用程序行为,自动调整各代龄的内存容量阀值,从而提高程序性能。

  垃圾收集器在APS.Net Web窗体和XML Web服务应用程序中的工作表现相当出色。对ASP.Net应用程序来说,当客户请求到达时,会有许多新的对象被构造,这些对象会根据客户的行为执行某些操作,然后结果返回客户。之后,所有用来响应客户请求的对象都将成为垃圾对象。这样,每一次垃圾收集都能回收许多内存。

编程控制垃圾收集器

  System.GC类型为我们的应用程序提供了直接控制垃圾收集器的一些方法。

  GC.MaxGeneration属性:返回托管堆支持的最大代龄,目前返回值为2。

  GC.GetGeneration(object obj)方法:返回int类型,获取一个对象的代龄。

  GC.GetGeneration(WeakReference)方法:返回int类型,获取一个弱引用对象的代龄。

  GC.Collect()方法:强制对所有代龄对象执行垃圾收集。大多数情况下,我们应该避免手动调用Collect方法,而应该让垃圾收集器根据自己的判断来执行。

  GC.Collect(int Generation)方法:强制对指定代龄的对象执行垃圾收集。

  GC.WaitForPendingFinalizers()方法:挂起执行线程,直到处理终止化可达队列的线程清空了该队列,并完成每个对象的Finalize方法调用为止。

  如下例代码:

  GC.Collect();  //强制执行垃圾收集
  GC.WaitForPendingFinalizers();  //等待第一次收集中发现的终止化对象的Finalize方法完成
  GC.Collect();  //将第一次收集中发现的终止化对象内存回收

大尺寸对象

  任何占用内存等于或超过85000字节的对象都被认为是大尺寸对象。大尺寸对象从一个特殊的大尺寸对象托管堆中分配。该托管堆中对象的终止化和内存释放行为与普通对象相同。但大尺寸对象不会被压缩,因为在托管堆中搬移85000字节以上的内存块会浪费CPU比较多的时间。

  另外,大尺寸对象总被认为是第2代对象,因此我们只应该为那些需要保存很长时间的资源创建大尺寸对象。分配生存期比较短的大尺寸对象将导致垃圾收集器频繁地收集第2代对象,这无疑会操作应用程序的性能。

你可能感兴趣的:(Microsoft)