第十三节:编程控制垃圾回收器

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调用

       

        }

 

    }

 

posted @ 2015-04-27 19:27  -祐扌戒恉-  阅读(224)  评论(0编辑  收藏  举报