2013-02-21 3 views
5

Мы используем веб-ферму с использованием .NET. Каждый веб-сервер содержит значительное количество статических объектов в своей памяти. Сбор мусора Gen 2 (GC) занимает 10-20 секунд, и он запускается каждые 5 минут. Мы столкнулись более или менее с теми же проблемами, с которыми столкнулся StackOverflow: http://samsaffron.com/archive/2011/10/28/in-managed-code-we-trust-our-recent-battles-with-the-net-garbage-collectorУведомления об утерянной коллекции мусора

В настоящий момент мы уменьшаем количество объектов в кеше. Однако это требует времени.

В то же время мы реализовали методы, документированные here, для получения уведомлений в .NET о приближении к GC. Цель состоит в том, чтобы вывести веб-сервер из фермы при приближении GC и включить его в ферму после завершения GC. Однако мы получаем уведомление только за 0,7% всех GC. Мы используем maxGenerationThreshold и largeObjectHeapThreshold 8. Мы пробовали другие пороговые значения, но количество пропущенных GC не изменилось. (http://msdn.microsoft.com/en-us/library/ms229357.aspx). GCLatencyMode является интерактивным (см. http://msdn.microsoft.com/en-us/library/system.runtime.gclatencymode.aspx). Здесь мы снова попытались использовать другие режимы GC (режим рабочей станции, пакет и т. Д.). И снова мы не получили уведомление для большинства GC.

Делаем ли мы что-то не так, или невозможно получить уведомление для каждого GC, который происходит? Как мы можем увеличить количество уведомлений?

Согласно 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) 
    { 
    } 
} 
+0

Не могли бы вы, возможно, разместить код, где вы регистрируетесь и слушать уведомлений GC? – Alex

+0

'GC.RegisterForFullGCNotification (gcThreshold, gcThreshold); // Запуск потока с помощью WaitForFullGCProc. thWaitForFullGC = новая тема (WaitForFullGCProc); thWaitForFullGC.Name = "HealthTestGCNotificationListenerThread (Threshold =" + gcThreshold + ")"; thWaitForFullGC.IsBackground = true; – kopernik

ответ

3

Примечание: Это больше комментарий, но включает в себя большой образец кода ,

Вы считаете, что пытаетесь получить свои уведомления GC по-другому? Джеффри Рихтер (CLR via C#) объясняет хороший способ получения уведомлений, он использует объект и проверяет его метод финализатора в том, что это такое.

Это класс: Он использует внутренние объекты, которые собираются, если соответствующее поколение соответствует (см. Например, new GenObject(0);). Или воскрешено для следующего более высокого поколения.

И вы просто подписаться на него с GCNotification.GCDone += GCDoneHandler;

public static class GCNotification 
    { 
     private static Action<Int32> s_gcDone = null; // The event's 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 */ } 
      } 
     } 
    } 
+0

Это хорошая идея, но, к сожалению, она уведомляет меня только после завершения GC. Он не уведомляет меня о каких-либо предстоящих сборках мусора ... – kopernik

Смежные вопросы