.Net 垃圾回收通知

有的公共语言运行库的完整垃圾回收 (即,第 2 代集合) 可能会影响性能的情况。 对于处理大量请求的服务器而言,此问题尤为突出;在这种情况下,长时间的垃圾回收可能会导致请求超时。 若要防止在重要时间段发生完整垃圾回收,可以让系统通知您即将发生完整垃圾回收,您可以采取措施将工作负荷重定向到其他服务器实例。 您也可以在当前服务器实例不需要处理请求时自己引发回收。

RegisterForFullGCNotification 方法注册一个通知,当运行时察觉到即将发生完整垃圾回收时将引发该通知。 此通知包含两部分:何时将发生完整垃圾回收以及完整垃圾回收何时完成。

警告说明警告

仅阻止垃圾回收引发通知。 当 <gcConcurrent> 配置元素处于启用状态,背景垃圾回收将不会引发通知。

若要确定何时引发了通知,请使用 WaitForFullGCApproachWaitForFullGCComplete 方法。 通常,可在 while 循环中使用这些方法来持续获取显示通知状态的 GCNotificationStatus 枚举。 如果该值为 Succeeded,则可以执行以下操作:

  • 为了响应使用 WaitForFullGCApproach 方法获取的通知,可以重定向工作负荷并可以自己引发回收。

  • 为了响应使用 WaitForFullGCComplete 方法获取的通知,可以使当前服务器实例再次可用于处理请求。 还可以收集信息。 例如,可以使用 CollectionCount 方法记录回收次数。

WaitForFullGCApproachWaitForFullGCComplete 方法应一起使用。 只使用其中一个方法可能导致不确定的结果。

完整垃圾回收

在发生以下任何一种情况时,运行时进行完整垃圾回收:

  • 提升至第 2 级的内存量已经足以进行下一次第 2 级回收。

  • 提升至大对象堆的内存量已经足以进行下一次第 2 级回收。

  • 其他原因导致第 1 级回收提升至第 2 级回收。

RegisterForFullGCNotification 方法中指定的阈值适用于前两种情况。 但在第一种情况中,由于以下两个原因,在与指定的阈值成比例的时间点您不总是能够收到通知。

  • 运行时不检查每个小型对象分配(出于性能原因)。

  • 只有第 1 级回收将内存提升至第 2 级。

第三种情况也增加了您在何时收到通知的不确定性。 可以在这段时间内对请求进行重定向,或者在系统可以更好地处理垃圾回收时由您自己引发垃圾回收,从而缓解在不恰当的时机发生完整垃圾回收所造成的不良影响。虽然这种做法不能提供完全的保障,但已证明是一种行之有效的方式。

通知阈值参数

RegisterForFullGCNotification 方法有两个参数用于指定第 2 级对象和大对象堆的阈值。 在达到这些值时,应引发垃圾回收通知。 下表介绍了这些参数。

参数

说明

maxGenerationThreshold

一个介于 1 和 99 之间的数字,指定基于提升至第 2 级的对象引发通知的时间。

largeObjectHeapThreshold

一个介于 1 和 99 之间的数字,指定基于在大对象堆中分配的对象引发通知的时间。

如果指定的值过高,则很有可能发生这样的情况:您虽然收到通知,但要等待很长一段时间之后运行时才会引发回收。 如果您自己引发回收,则回收的对象可能比运行时引发回收时回收的对象要多。

如果指定的值过低,则运行时可能在您来不及收到通知时就已引发回收。

示例

Cc713687.collapse_all(zh-cn,VS.110).gif说明

在下面的示例中,有一组服务器为传入的 Web 请求提供服务。 为了模拟处理请求的工作负荷,该示例将一些字节数组添加到 List<T> 集合中。 每个服务器都注册一个垃圾回收通知,然后在 WaitForFullGCProc 用户方法上启动一个线程,以持续监视由 WaitForFullGCApproachWaitForFullGCComplete 方法返回的 GCNotificationStatus 枚举。

当引发通知时,WaitForFullGCApproachWaitForFullGCComplete 方法调用各自的事件处理用户方法:

  • OnFullGCApproachNotify

    此方法调用 RedirectRequests 用户方法,该用户方法指示请求队列服务器挂起向服务器发送请求的操作。 该示例通过将类级变量 bAllocate 设置为 false 以便不再分配对象,对此操作进行模拟。

    接下来,调用 FinishExistingRequests 用户方法完成对挂起的服务器请求的处理。 该示例通过清除 List<T> 集合来模拟此操作。

    最后,会由于工作负荷变轻而引发垃圾回收。

  • OnFullGCCompleteNotify

    此方法调用用户方法 AcceptRequests 以继续接受请求,因为服务器不再容易遭遇完整垃圾回收。 该示例通过将 bAllocate 变量设置为 true 以便可以继续将对象添加到 List<T> 集合,对此操作进行模拟。

下面的代码包含示例的 Main 方法。

using System; using System.Collections.Generic; using System.Threading; namespace GCNotify
{ class Program
    { // Variable for continual checking in the  // While loop in the WaitForFullGCProc method. static bool checkForNotify = false; // Variable for suspending work  // (such servicing allocated server requests) // after a notification is received and then  // resuming allocation after inducing a garbage collection. static bool bAllocate = false; // Variable for ending the example. static bool finalExit = false; // Collection for objects that  // simulate the server request workload. static List<byte[]> load = new List<byte[]>(); public static void Main(string[] args)
        { try { // Register for a notification.  GC.RegisterForFullGCNotification(10, 10);
                Console.WriteLine("Registered for GC notification.");

                checkForNotify = true;
                bAllocate = true; // Start a thread using WaitForFullGCProc. Thread thWaitForFullGC = new Thread(new ThreadStart(WaitForFullGCProc));
                thWaitForFullGC.Start(); // While the thread is checking for notifications in // WaitForFullGCProc, create objects to simulate a server workload. try { int lastCollCount = 0; int newCollCount = 0; while (true)
                    { if (bAllocate)
                        {
                            load.Add(new byte[1000]);
                            newCollCount = GC.CollectionCount(2); if (newCollCount != lastCollCount)
                            { // Show collection count when it increases: Console.WriteLine("Gen 2 collection count: {0}", GC.CollectionCount(2).ToString());
                                lastCollCount = newCollCount;
                            } // For ending the example (arbitrary). if (newCollCount == 500)
                            {
                                finalExit = true;
                                checkForNotify = false; break;
                            }
                        }
                    }

                } catch (OutOfMemoryException)
                {
                    Console.WriteLine("Out of memory.");
                }


                finalExit = true;
                checkForNotify = false;
                GC.CancelFullGCNotification();

            } catch (InvalidOperationException invalidOp)
            {

                Console.WriteLine("GC Notifications are not supported while concurrent GC is enabled.\n" + invalidOp.Message);
            }
        } public static void OnFullGCApproachNotify()
        {

            Console.WriteLine("Redirecting requests."); // Method that tells the request queuing  // server to not direct requests to this server.  RedirectRequests(); // Method that provides time to  // finish processing pending requests.  FinishExistingRequests(); // This is a good time to induce a GC collection // because the runtime will induce a full GC soon. // To be very careful, you can check precede with a // check of the GC.GCCollectionCount to make sure // a full GC did not already occur since last notified. GC.Collect();
            Console.WriteLine("Induced a collection.");

        } public static void OnFullGCCompleteEndNotify()
        { // Method that informs the request queuing server // that this server is ready to accept requests again. AcceptRequests();
            Console.WriteLine("Accepting requests again.");
        } public static void WaitForFullGCProc()
        { while (true)
            { // CheckForNotify is set to true and false in Main. while (checkForNotify)
                { // Check for a notification of an approaching collection. GCNotificationStatus s = GC.WaitForFullGCApproach(); if (s == GCNotificationStatus.Succeeded)
                    {
                        Console.WriteLine("GC Notification raised.");
                        OnFullGCApproachNotify();
                    } else if (s == GCNotificationStatus.Canceled)
                    {
                        Console.WriteLine("GC Notification cancelled."); break;
                    } else { // This can occur if a timeout period // is specified for WaitForFullGCApproach(Timeout)  // or WaitForFullGCComplete(Timeout)  // and the time out period has elapsed.  Console.WriteLine("GC Notification not applicable."); break;
                    } // Check for a notification of a completed collection. s = GC.WaitForFullGCComplete(); if (s == GCNotificationStatus.Succeeded)
                    {
                        Console.WriteLine("GC Notifiction raised.");
                        OnFullGCCompleteEndNotify();
                    } else if (s == GCNotificationStatus.Canceled)
                    {
                        Console.WriteLine("GC Notification cancelled."); break;
                    } else { // Could be a time out. Console.WriteLine("GC Notification not applicable."); break;
                    }
                }


                Thread.Sleep(500); // FinalExit is set to true right before  // the main thread cancelled notification. if (finalExit)
                { break;
                }
            }

        } private static void RedirectRequests()
        { // Code that sends requests // to other servers. // Suspend work. bAllocate = false;

        } private static void FinishExistingRequests()
        { // Code that waits a period of time // for pending requests to finish. // Clear the simulated workload. load.Clear();

        } private static void AcceptRequests()
        { // Code that resumes processing // requests on this server. // Resume work. bAllocate = true;

        }
    }
}

转载于:https://my.oschina.net/dgwutao/blog/146054

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值