2013-02-21 79 views
5

हम .NET का उपयोग कर एक वेब फार्म चला रहे हैं। प्रत्येक वेब सर्वर में इसकी स्मृति में स्थिर वस्तुओं की काफी मात्रा होती है। एक जनरल 2 कचरा संग्रह (जीसी) 10-20 सेकंड लेता है और यह हर 5 मिनट में चलता है। हम उसी समस्या में अधिक या कम भाग गए जो StackOverflow में भाग गया: http://samsaffron.com/archive/2011/10/28/in-managed-code-we-trust-our-recent-battles-with-the-net-garbage-collectorमिस्ड कचरा संग्रह अधिसूचनाएं

फिलहाल, हम कैश में ऑब्जेक्ट्स की संख्या को कम कर रहे हैं। हालांकि, इसमें समय लगता है।

उसी समय, हमने जीसी के पास आने के बारे में .NET में अधिसूचनाएं प्राप्त करने के लिए here दस्तावेज किए गए तरीकों को लागू किया। लक्ष्य जीसी के आने के बाद खेत में शामिल होने और जीसी खत्म होने के बाद इसे खेत में शामिल करने का लक्ष्य है। हालांकि, हमें केवल सभी जीसी के 0.7% के लिए अधिसूचना मिलती है। हम एक अधिकतम जनरेशन थ्रेसहोल्ड और bigObjectHeapThreshold 8 का उपयोग कर रहे हैं। हमने अन्य थ्रेसहोल्ड की कोशिश की, लेकिन मिस्ड जीसी की मात्रा में बदलाव नहीं आया।

हम समवर्ती सर्वर कचरा संग्रह (http://msdn.microsoft.com/en-us/library/ms229357.aspx) का उपयोग कर रहे हैं। जीसीलाटेंसी मोड इंटरएक्टिव है (http://msdn.microsoft.com/en-us/library/system.runtime.gclatencymode.aspx देखें)। यहां फिर से, हमने अन्य जीसी मोड (वर्कस्टेशन मोड, बैच इत्यादि) का उपयोग करने की कोशिश की। और फिर हमें अधिकांश जीसी के लिए अधिसूचना नहीं मिली।

क्या हम कुछ गलत कर रहे हैं, या क्या हर जीसी के लिए अधिसूचना प्राप्त करना असंभव है? हम अधिसूचनाओं की संख्या कैसे बढ़ा सकते हैं?

http://assets.red-gate.com/community/books/assets/Under_the_Hood_of_.NET_Management.pdf के अनुसार, शुरुआत में जीसी 2 जीबी हिट होने पर जीसी ट्रिगर होता है। हमारे पास बहुत सी रैम है, इसलिए यदि हम इस दहलीज को मैन्युअल रूप से उच्च स्तर पर सेट कर सकते हैं, तो इस सीमा तक पहुंचने में अधिक समय लगेगा और मेरी समझ में अधिसूचना प्राप्त करने में संभावना बढ़ेगी। क्या इस दहलीज को संशोधित करने का कोई तरीका है?

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

साथ यह करने के लिए सदस्यता आप शायद कोड जहां आप रजिस्टर और जीसी सूचनाओं के लिए सुनने के बाद सकते हैं? – Alex

+0

'जीसी। रजिस्ट्रारफॉरफुलजीसी नोटिफिकेशन (जीसी थ्रेसहोल्ड, जीसी थ्रेसहोल्ड); // WaitForFullGCProc का उपयोग करके थ्रेड प्रारंभ करें। thWaitForFullGC = नया थ्रेड (WaitForFullGCProc); thWaitForFullGC.Name = "HealthTestGCNotificationListenerThread (थ्रेसहोल्ड =" + gcThreshold + ")"; thWaitForFullGC।IsBackground = सच है; – kopernik

उत्तर

3

नोट: यह एक टिप्पणी के और अधिक है, लेकिन एक बड़ी कोड नमूना शामिल ।

क्या आपने अपनी जीसी अधिसूचनाओं को किसी अन्य तरीके से प्राप्त करने का प्रयास किया है? जेफरी रिक्टर (सी # के माध्यम से सीएलआर) अधिसूचनाएं प्राप्त करने का एक अच्छा तरीका बताता है, यह किसी ऑब्जेक्ट का उपयोग करता है और इसकी अंतिम विधि को जांचता है कि यह किस पीढ़ी में है।

यह कक्षा है: यह आंतरिक वस्तुओं का उपयोग करता है जो आपूर्ति किए गए पीढ़ी के मिलान (उदाहरण के लिए 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

यह एक अच्छा विचार है, लेकिन दुर्भाग्य से यह केवल मुझे सूचित करता है के बाद जीसी समाप्त हो गया है। यह मुझे किसी भी आगामी कचरा संग्रह के बारे में सूचित नहीं करता है ... – kopernik