CLR中的垃圾回收机制

  CLR中采用代(generation)来作为其垃圾回收的一种机制,其唯一的目的是提升程序的性能。基予代的垃圾回收器有以下假设:

  ·对象越新,其生存周期越短。

  ·对象越老,其生存周期越长。

  ·回收堆的一部分,速度快于回收整个堆。

  托管堆在初始化时不包括任何对象。添加到堆的对象称为第0代对象。下图展示一个新启动的应用程序,其分配了五个对象(A-E)。运行一段时间后,C、E变为垃圾。

  CLR初始化时,它会为第0代对象选择一个初始容量,假定为256KB。当分配对象时,一旦第0代超出这个数值,就必须启动一次垃圾回收。假如A-E刚好占用256KB,分配F时,会启动垃圾回收。此时,C和E被判断为垃圾,所以压缩D,使之与B相邻(定义容量为256是因为所有这些对象都可以放到CPU的L2缓存,使内存的压缩能以非常快的速度完成)。此时尚存活的对象A、B、D变为第一代对象。

  经过一次垃圾回收后,第0代就不包含任何对象了,此时新对象分配到第0代。假如新分配了F-K,且B、H、G变为垃圾。

  假如分配新对象L时造成第0代超出预算,此时启动垃圾回收检查第0代。而且其还要为第一代选择一个容量预算,假设为2M。开始垃圾回收时,垃圾回收器会检查第一代的占用的内存,此时由于远小于2M,所以只检查第0代的对象。基于假设----新创建的对象生存期短,第0代会包含大量垃圾,所以对第0代进行垃圾回收可以回收较多的内存,垃圾回收器会忽略第一代的对象,从而加快垃圾回收速度。经过一次垃圾回收后,堆内如下图所示:

  我们可以看到,幸存下来的0代变成了1代,由于垃圾回收器没有进行1代的检查,所以B占用的内存并没有被回收,此时0代没有任何对象。假如堆中又增加了L-O,然后G,L,M成为垃圾:

  假如分配P导致第0代超出预算,垃圾回收启动。由于1代中对象占用的内存小于2MB,此时垃圾回收器仍然只回收0代。回收后如下图:

  如此下去,1代会慢慢的增长,如果其内存占据2MB,此时对堆中分配对象P-S,使第0代超出其预算,如下图:

  当对堆内分配对象T时,由于0代已满,对其进行垃圾回收,此时垃圾回收器发现1代超过了2MB内存,所以此次对一代和0代同时进行垃圾检查。两代都回收后,堆内情况如下:

  像前面相同,0代提升到1代,1代提升到2代,此时0代又空出来了,再次接受新的对象。

  CLR的托管堆只支持三代:0、1、2。CLR初始化时,会为每一代选择预算,大约依次为256KB,2MB,10MB,预算越大,垃圾回收频率越低,

  

原文地址:https://www.cnblogs.com/xuekai-to-sharp/p/3423589.html