2013-02-21 33 views
5

.NET kullanarak bir web grubu çalıştırıyoruz. Her web sunucusu, hafızasında önemli miktarda statik nesne barındırır. Gen 2 çöp toplama (GC) 10-20 saniye sürüyor ve her 5 dakikada bir çalışıyor. StackOverflow'un çalıştırdığı aynı sorunlara daha fazla veya daha az rastladık: http://samsaffron.com/archive/2011/10/28/in-managed-code-we-trust-our-recent-battles-with-the-net-garbage-collectorÖzürlü Çöp Toplama Bildirimleri

Şu anda önbellekteki nesne sayısını azaltıyoruz. Ancak, bu zaman alır.

Aynı zamanda, .NET'te GC'lere yaklaşma konusunda bildirim almak için here belgelenen yöntemleri uyguladık. Amaç, bir GC yaklaştığında bir web sunucusunu çiftlik dışına çıkarmak ve GC bittikten sonra çiftliğe dahil etmektir. Ancak, yalnızca tüm GC'lerin% 0.7'si için bir bildirim alıyoruz. Biz bir maxGenerationThreshold ve 8 büyükObjectHeapThreshold kullanıyoruz. Diğer eşikleri denedik ama cevapsız GC'ler değişmedi.

Eşzamanlı sunucu çöp toplama (http://msdn.microsoft.com/en-us/library/ms229357.aspx) kullanıyoruz. GCLatencyMode, Etkileşimli (bkz. http://msdn.microsoft.com/en-us/library/system.runtime.gclatencymode.aspx). Burada yine diğer GC modlarını kullanmaya çalıştık (İş İstasyonu modu, Parti vb.). Ve yine çoğu GC'ler için bir bildirim almadık.

Yanlış bir şey mi yapıyoruz, yoksa gerçekleşen her GC için bildirim almak imkansız mı? Bildirimlerin sayısını nasıl artırabiliriz?

http://assets.red-gate.com/community/books/assets/Under_the_Hood_of_.NET_Management.pdf'a göre, başlangıçta Gen2 ~ 10 MB isabet ettiğinde bir GC tetiklenir. Çok fazla RAM'imiz var, bu yüzden bu eşiği daha yüksek bir seviyeye ayarlayabilirsek, bu eşiğe ulaşmak daha fazla zaman alacaktır ve benim anlayışımda olasılık bir bildirim almak için artacaktır. Bu eşiği değiştirmenin bir yolu var mı?

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

WaitForFullGCProc():

Bu

bildirimleri kaydeder ve dinler kodu

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

ile abone? – Alex

+0

'GC.RegisterForFullGCNotification (gcThreshold, gcThreshold); // WaitForFullGCProc kullanarak bir konu başlat. thWaitForFullGC = yeni Thread (WaitForFullGCProc); thWaitForFullGC.Name = "HealthTestGCNotificationListenerThread (Eşik =" + gcThreshold + ")"; thWaitForFullGC.IsBackground = true; – kopernik

cevap

3

Not: Bu daha fazla bir yorum ama büyük bir kod örneğini içerir .

GC bildirimlerinizi başka bir yolla almaya çalışmayı düşündünüz mü? Jeffrey Richter (C# ile CLR) bildirimleri almanın iyi bir yolunu açıklar, bir nesneyi kullanır ve hangi nesilde olduğunu finalizer yöntemini kontrol eder.

Bu, sınıftır: Ürünle birlikte verilen nesle eşleşiyorsa toplanan (örneğin, bkz. new GenObject(0);) veya sonraki sonraki nesil için yeniden dirilen dahili nesneler kullanılır.

Ve sadece muhtemelen kayıt ve GC bildirimleri için dinleme kodu gönderir misiniz 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

Bu güzel bir fikir, ancak maalesef sadece GC bittikten sonra beni bilgilendiriyor. Yaklaşan çöp koleksiyonları hakkında bana haber vermez ... – kopernik

İlgili konular