Lost Recycle Bin Notifications

We use a web farm using .NET. Each web server contains a significant number of static objects in it. Gen 2 (GC) garbage collection takes 10-20 seconds and it starts every 5 minutes. We used more or less the same problems that StackOverflow encountered: http://samsaffron.com/archive/2011/10/28/in-managed-code-we-trust-our-recent-battles-with-the- net-garbage-collector

We are currently reducing the number of objects in the cache. However, this takes time.

At the same time, we implemented the methods described here to receive notifications in .NET about approaching the GC. The goal is to get the web server out of the farm when the GC approaches and include it in the farm after the GC completes. However, we only receive a notification for 0.7% of all GCs. We use maxGenerationThreshold and largeObjectHeapThreshold 8. We tried other thresholds, but the number of skipped GCs did not change.

We use shared server garbage collection ( http://msdn.microsoft.com/en-us/library/ms229357.aspx ). GCLatencyMode is interactive (see http://msdn.microsoft.com/en-us/library/system.runtime.gclatencymode.aspx ). Here we again tried to use other GC modes (workstation mode, package, etc.). Again, we did not receive a notification for most GC.

Are we doing something wrong, or is it impossible to get a notification for each GC? How can we increase the number of notifications?

http://assets.red-gate.com/community/books/assets/Under_the_Hood_of_.NET_Management.pdf, GC , Gen2 ~ 10 . , , , , , , , . ?

, :

GC.RegisterForFullGCNotification(gcThreshold, gcThreshold);
// Start a thread using WaitForFullGCProc.
thWaitForFullGC = new Thread(WaitForFullGCProc);
thWaitForFullGC.Name = "HealthTestGCNotificationListenerThread (Threshold=" + gcThreshold + ")";
thWaitForFullGC.IsBackground = true;

WaitForFullGCProc():

    private void WaitForFullGCProc()
{
    try
    {
        while (!gcAbort)
        {
            // Check for a notification of an approaching collection.
            GCNotificationStatus s;
            do
            {
                int timeOut = CheckForMissedGc() > 0 ? 5000 : (10 * 60 * 1000);
                s = GC.WaitForFullGCApproach(timeOut);
                if (this.GcState == GCState.InducedUnnotified)
                {
                    // Set the GcState back to okay to prevent the message from staying in the ApplicationMonitoring.
                    this.GcState = GCState.Okay;
                }
            } while (s == GCNotificationStatus.Timeout);

            if (s == GCNotificationStatus.Succeeded)
            {
                SetGcState(GCState.Approaching, "GC is approaching..");
                gcApproachNotificationCount++;
            }
            else
            {
                ...
            }

            Stopwatch stopwatch = Stopwatch.StartNew();
            s = GC.WaitForFullGCComplete((int)PrewarnTime.TotalMilliseconds);
            long elapsed = stopwatch.ElapsedMilliseconds;

            if (s == GCNotificationStatus.Timeout)
            {
                if (this.ForceGCWhenApproaching && !this.IsInGc && !this.IsPeriodicGcApproaching)
                {
                    this.IsInGc = true;
                    GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, blocking: true);
                    GC.WaitForPendingFinalizers();
                    elapsed = stopwatch.ElapsedMilliseconds;
                    this.IsInGc = false;
                }
            }
        }
        gcAbort = false;
    }
    catch (Exception e)
    {
    }
}
+5
1

. , .

GC -? (CLR via #) , , .

: , , (. new GenObject(0); .) .

GCNotification.GCDone += GCDoneHandler;

 public static class GCNotification
    {
        private static Action<Int32> s_gcDone = null; // The event field
        public static event Action<Int32> GCDone
        {
            add
            {
                // If there were no registered delegates before, start reporting notifications now
                if (s_gcDone == null) { new GenObject(0); new GenObject(1); new GenObject(2); }
                s_gcDone += value;
            }
            remove { s_gcDone -= value; }
        }
        private sealed class GenObject
        {
            private Int32 m_generation;
            public GenObject(Int32 generation) { m_generation = generation; }
            ~GenObject()
            { // This is the Finalize method
                // If this object is in the generation we want (or higher),
                // notify the delegates that a GC just completed
                if (GC.GetGeneration(this) >= m_generation)
                {
                    Action<Int32> temp = Volatile.Read(ref s_gcDone);
                    if (temp != null) temp(m_generation);
                }
                // Keep reporting notifications if there is at least one delegate registered,
                // the AppDomain isn't unloading, and the process isn’t shutting down
                if ((s_gcDone != null)
                && !AppDomain.CurrentDomain.IsFinalizingForUnload()
                && !Environment.HasShutdownStarted)
                {
                    // For Gen 0, create a new object; for Gen 2, resurrect the object
                    // & let the GC call Finalize again the next time Gen 2 is GC'd
                    if (m_generation == 0) new GenObject(0);
                    else GC.ReRegisterForFinalize(this);
                }
                else { /* Let the objects go away */ }
            }
        }
    }
+3

All Articles