C# 托管堆和垃圾回收器GC

时间:2022-06-05 07:10:47

这里我们讨论的两个东西:托管堆和垃圾回收器,前者是负责创建对象并控制这些对象的生存周期,后者负责回收这些对象。

一、托管堆分配资源

CLR要求所有的对象都从托管堆分配。进程初始化时,CLR划出一个地址空间区域作为托管堆。CLR还要维护一个指针P,该指针指向下一个对象在堆中的分配位置。

那么我们进一步深入看看创建一个对象(也就是new 一个对象)时CLR做了哪些工作呢。

1、计算类型字段需要的字节数。

2、加上对象开销所需要的字节数,每个对象都有两个开销:类型对象指针和同步块索引

3、CLR检查区域中可用空间够不够,如果够就在指针P指向的地址放入对象。

4、调用类型的构造器,new操作符返回对象引用。

5、返回对象引用之前指针P会移到下个对象放入托管堆时的地址。

二、垃圾回收器回收资源

应用程序调用new操作符创建对象时,可能没有足够的地址空间来分配该对象,发现空间不够,CLR就执行回收.

在讲GC时我们要明白几个概念:

  根:将所有引用类型的变量都称为根

可达和不可达:至少有一个根在引用对象时我们称这个对象可达,否则我们称之为不可达。

C# 托管堆和垃圾回收器GC

正式开始垃圾回收,我们参考上面的这个图,图中A,B、C、D、E就是我们托管堆上的对象,现在只有A和C两个对象被引用,E被C引用,步骤如下:

1、CLR开始GC时,前先暂停进程中的所有线程。

2、CLR遍历堆中的所有对象,将所有对象都标记为0,表示所有对象都应删除。

3、CLR检测所有活动根,任何根如果引用了堆上的对象CLR就会标记那个对象为1.注意这里的C引用了E,在标记C的时候还要判断E是否标识了1,如果标记了就不再标记,如果没有标记则标记为1

4、标记完后堆中的对象要么是已标记1,要么是未标记0,已标记的对象为可达的,未标记的对象为不可达的,GC会接下来会删除这些未标记的对象,也就是标记为0的对象

5、GC将对象删除后进入压缩阶段,将所有对象集中在一个连续的类存中,解决了本机的空间碎片化的问题,压缩完成后,CLR恢复应用程序的所有线程。

至此,一个对象的创建到回收就完成了。