C#基础:.NET中GC的运行机制
一、什么是GC
GC是垃圾回收(Garbage Collector)的缩写。GC可以说是.NET众多机制中最为重要的,对程序员代码书写方式影响最大的机制。在CLR规范制定之初,所有机制都还在斟酌的时候,垃圾回收已经被确定会存在于.NET框架之中。
.NET的程序大部分被称为被托管的代码。托管的意义很广泛,其中重要的一点就是代码中对象内存的分配和释放是由.NET内存管理和垃圾回收机制统一管理的。和传统C++的程序员不同,C#或者其他面向.NET框架语言的程序员不再需要时刻警惕内存的泄露,因为托管对象的内存最终会被垃圾回收释放掉,尽管不同的编写方式会产生不同的运行效率。
这里指的是受托管的对象,当使用了一些非托管的资源时,程序员仍然需要手动地释放它们。
所谓的垃圾回收,是指.NET清理托管堆上不会再被使用的对象内存,并且移动仍在被使用的对象,使它们紧靠托管堆的一边。下图展示了一次垃圾回收后托管堆上的变化。
如上图所示,GC的执行过程分为两个基本动作:
- 找到所有不再被使用的对象:对象A和对象C,并标记为垃圾。
- 移动扔在被使用的对象:对象B和对象D。这样对象A和对象C的内存空间就被腾空出来了,以备下次分配的时候使用。
这里简化了GC的执行过程,省略了包含Finalize方法对象的处理,以及大对象分配的特殊性。
垃圾回收由.NET垃圾回收机制来控制,理论上当托管堆内存不够时,.NET会运行垃圾回收来得到更多的可分配内存,微软并没有公开这一部分的算法,程序员无法精确得知垃圾回收的执行时间。在通常情况下,程序员不需要干涉垃圾回收的执行。不过CLR仍然提供了一个手动执行垃圾回收的方法:GC.Collect()方法。当程序员需要在某一批对象不再使用并且及时释放内存时,可以调用该方法来实现。
垃圾回收涉及了对象块的移动、遍历找到不被使用的对象,这是一个相当耗费资源的过程。所有的程序优化策略都会有一条:尽量减少垃圾回收的负担和次数。在编写程序的过程中,应该注意避免不必要的资源分配,因为这意味着多余的垃圾回收的负担。
二、总结
垃圾回收是指收集释放托管堆上不再被使用的内存对象。其过程基本包括:通过算法找到不再被使用的对象、移动对象使所有扔被使用的对象紧靠托管堆的一边和调整各个状态变量。
垃圾回收的运行成本较高,对性能的影响较大。程序员在编写.NET代码时,应该避免不必要的内存分配,尽量减少或避免使用GC.Collect来执行垃圾回收。