System.GC类型允许应用程序在某种程度上直接控制垃圾回收。例如:可以读取GC.MaxGeneration属性来查询托管堆支持的最大代数;该属性总是返回2。
还可以调用以下静态方法来强迫执行一次垃圾回收:
public static void Collect();
public static void Collect(int generation);
public static void Collect(int generation, GCCollectionMode mode);
第二个方法允许指定回收那一代吗,传递0导致第0代回收,传递1导致第1代和第0代回收,传递2导致第2代、第1代、第0代回收。无参的版本导致对所有代执行一次回收。
第三个方法重载版本允许传递一个代和一个GCCollectionMode。下面总结各种GC回收模式符号。
GCCollectionMode枚举定义的符号:
Default :等同于不传递任何符号名称。目前还等同与传递Forced,但CLR未来的版本可能进行修改
Forced:强迫回收指定的代(以及低于它的代)
Optimized 只有在能够释放大量内存或者能减少大量碎片化的前提下,才执行回收。如果垃圾回收效果不佳,当前调用就没有任何效果。
大多数情况下应避免调用任何Collect方法;最好是让垃圾回收器自行斟酌执行,并根据实际的应用程序的行为来调整各个代的预算。但是,如果你要写一个CUI(控制台用户界面)和GUI(图形用户界面)应用程序,应用程序代码将拥有进程和那个进程中的CLR.对于这种应用程序,你可能建议在特定时间发生一次垃圾回收;为此,请将GCCollectionMode设为Optimized并调用Collect。一般情况下,Default和Forced这两种模式是供调试和测试用的。
例如,假设刚才发生了某个非重复性的事件,并导致大量旧对象死亡,就可考虑手动调用一次Collect方法。对于非重复性的事件,垃圾回收器基于历史而对未来的预测可能不会准确。所以在这种情况下调用Collect方法时合适的。
例如:在应用程序初始化完成以后,或者在用户保存了一个数据文件后,应用程序就适合对所有代强制执行一次垃圾回收。一个Window窗体宿主在网页上时,每次页面卸载后,都要执行一次完全的垃圾回收,不要为了改善应用程序的响应时间而显示调用Collect方法;只应处于减少进程工作集的目的而调用它。
GC类还提供了一个WaitForPendingFinalizers方法。该方法会挂起调用线程,直到处理freachable队列的线程清空该队列,完成对每个对象的Finalize方法的调用。在大多数应用程序中就没有必要调用该方法,但我见过下面这样的代码:
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
以上代码强制开始一次垃圾回收。回收完毕后,不需要终结的对象的内存将被回收。但需要终结的对象的内存还不能回收。第一个Collect调用返回后,专门负责终结操作的那个线程以异步方式调用Finalize方法。对WaitForPendingFinalizers方法的调用使应用程序线程进入睡眠状态。直到所有Finalize方法调用完毕。WaitForPendingFinalizers方法返回后,所有被终结的对象都以成为垃圾。这时,第二个Collect调用强制开始另一次垃圾回收,从而回收那些垃圾。
对于某些应用程序(尤其是喜欢在内存中容纳大量对象的服务器应用程序),如果对包含第2代在内的对象执行完全的垃圾回收,花费的时间可能过长。如果一次回收要花很长的时间才能完成,客户端请求可能会超时。为了适应这种应用程序的需求,GC类提供了一个RegisterForFullGCNotification方法。利用这个方法和一些额外的辅助方法(WaitForFullGCApproach、 WaitForFullGCComplete、 CancelFullGCNotification)应用程序会在垃圾回收器即将执行一次垃圾回收时收到通知。然后,应用程序可调用GC.Collect在一个更恰当的时间强制执行一次回收。应用程序也可与另一个服务器通信,对客户端的请求进行更好的负载平移。
最后,GC类还提供了两个静态方法来辅助你判断对象当前在哪一代中:
int GetGeneration(object obj);
int GetGeneration(WeakReference wo);
第一个版本是获取一个对象引用作为参数,第二版本是获取WeakReference引用作为参数。这两个方法返回的是0到GC.MaxGeneration的一个值。
一下代码有助于理解代的工作原理:
sealed class GenObj
{
~GenObj()
{
Console.WriteLine("In Finalize method");
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Maximun generation:" + GC.MaxGeneration);
Object o = new GenObj();
Console.WriteLine("Gen" + GC.GetGeneration(o));//0
//执行一次垃圾回收提升对象代
GC.Collect();
Console.WriteLine("Gen" + GC.GetGeneration(o));//1
GC.Collect();
Console.WriteLine("Gen" + GC.GetGeneration(o));//2
GC.Collect();
Console.WriteLine("Gen" + GC.GetGeneration(o));//2
o = null;
Console.WriteLine("Collecting Gen 0");
GC.Collect(0);//回收第0代
GC.WaitForPendingFinalizers();//Finalize未调用
Console.WriteLine("Collection Gens 0, and 1");
GC.Collect(1);//回收第0代和第1代
GC.WaitForPendingFinalizers();//Finalize未调用
Console.WriteLine("Collection Gens 0, 1 and 2");
GC.Collect(2);
GC.WaitForPendingFinalizers();//Finalize调用
}
}