2011-06-04 15 views
8

मैं हाल ही में एक WCF Windows सेवा के स्वामित्व है कि देखने डेटा पुनः प्राप्त करने के लिए निम्न स्थिर उपयोगिता वर्ग का गहन उपयोग करता निकाल दिया है:यह कोड मेमोरी रिसाव क्यों कर रहा है?

public static class Utility 
    { 

     //begin code that causes increased memory consumption 
     private static Dictionary<string, ErrorData> _errorData; 

     internal static Dictionary<string, ErrorData> ErrorData 

     { 
      get 
      { 
       if (_errorData == null) 
       { 
        _errorData = GetErrorData(); 
       } 
       return _errorData; 
      } 

     } 
     //end code that causes increased memory consumption 

     /// GetErrorData method to get error messages from error xml 
     /// </summary>   
     /// <returns>Dictionary of Error messages value for different fields.</returns>   
     internal static Dictionary<string, ErrorData> GetErrorData() 
     { 
      Dictionary<string, ErrorData> data = null; 


       XmlDocument doc = LoadXmlDocument(Constants.ErrorMessagesFileName); 
       XmlNodeList errorNode = doc.SelectNodes("/ErrorMessages/Error"); 
       data = new Dictionary<string, ErrorData>(); 

       foreach (XmlNode node in errorNode) 
       { 
        ErrorData errorValues = new ErrorData(); 
        errorValues.FieldName = node.Attributes["FieldName"].Value; 
        errorValues.ErrorMessage = node.Attributes["ErrorMessage"].Value; 
        data.Add(node.Attributes["code"].Value, errorValues); 
       } 


      return data; 
     } 
     internal static XmlDocument LoadXmlDocument(string xmlFileName) 
     { 
      XmlDocument doc = null; 
      try 
      { 
       if (HttpRuntime.Cache[xmlFileName] == null) 
       { 
        doc = new XmlDocument(); 
        doc.Load(Constants.Folderpath + "\\" + xmlFileName); 
        HttpRuntime.Cache.Insert(xmlFileName, doc); 
       } 
       else 
       { 
        doc = (XmlDocument)HttpRuntime.Cache[xmlFileName]; 
       } 
      } 
      catch (Exception ex) 
      { 
       //log 
      } 
      return doc; 
     } 
    } 

आप देख सकते हैं, स्थिर ErrorData संपत्ति एक निजी समर्थन का उपयोग करता है खेत। ErrorData एक शब्दकोश है जिसे फाइल सिस्टम पर एक्सएमएल संसाधन का उपयोग करके बनाया गया है, यही कारण है कि फ़ाइल की सामग्री HttpRuntime में संग्रहीत की जाती है। प्रारंभिक पुनर्प्राप्ति पर कैश करें।

सामान्य भार के तहत, सेवा लगभग 120 एमबी रैम का उपभोग करती है।

किसी बिंदु पर, एक टीम के सदस्य को आलसी लोड किए गए स्थैतिक क्षेत्र द्वारा समर्थित स्थिर संपत्ति बनाकर अनुकूलन का एक और स्तर पेश करने की आवश्यकता महसूस हुई। वैसे भी, कहा गया स्थिर क्षेत्र की उपस्थिति सेवा के लिए केवल कुछ कॉल के बाद एक गंभीर स्मृति रिसाव (500 एमबी +) का कारण बनती है।

जिस समय मैं स्थिर क्षेत्र और संपत्ति को हटाता हूं (क्लाइंट इसके बजाय उपयोगिता को कॉल करता है। गेट एररडाटा()), स्मृति खपत सामान्य स्तर पर वापस जाती है।

क्या कोई यह समझा सकता है कि इस स्थिर क्षेत्र की उपस्थिति मेमोरी रिसाव क्यों कर रही है? डब्ल्यूसीएफ सेवा InstanceContextMode.PerCall के साथ चल रही है, अगर इससे कोई फर्क पड़ता है।

बहुत धन्यवाद।

+0

आप कैसे जानते हैं कि यह स्मृति रिसाव पैदा कर रहा है? क्या यह सिर्फ बहुत सारी मेमोरी का उपयोग नहीं कर रहा है और इसे स्थिर रखता है क्योंकि यह स्थैतिक है? आपकी सेवा का क्या चल रहा है? क्या यह पर्कल है? सिंगलटन? सत्र? –

+1

क्या यह वास्तव में एक स्मृति रिसाव है या यह है कि जीसी पर्याप्त नहीं चल रहा है, या स्मृति को जारी करने के लिए आवश्यक नहीं मानता है। –

+1

DEBUG मोड या रिलीज मोड में चल रहे हैं? DEBUG मोड उन स्थितियों में रिसाव करेगा जो रिलीज मोड नहीं करेंगे। – Felan

उत्तर

0

मुझे पूरी तरह से यकीन नहीं है कि जब आप परिवर्तन के बारे में बात करते हैं तो कौन सा कोड बदलता है। हालांकि, कोड को पढ़ने से मेरा अनुमान यह है कि आप GetErrorData को एक से अधिक बार कॉल करना समाप्त कर देते हैं, और शब्दकोश केवल डुप्लिकेट प्रविष्टियों के साथ भर जाता है। यदि आप लॉगिंग कोड जोड़ते हैं, तो कौन सा कोड बार-बार दर्ज किया जाता है?

मार्टिन

1

त्रुटि फ़ाइल बहुत बड़ी है, तो स्थिर संस्करण स्मृति में विशाल XML दस्तावेज़ को लोड करता है और यह कभी नहीं जारी करता है। पहले, अगर क्लाइंट्स GetErrorData() कहलाता था, तो डेटा स्मृति में लोड हो गया था और लौटाया गया था, स्मृति को साफ़ करना।

यहां कोई सिंक्रनाइज़ेशन नहीं है, इसलिए यदि स्थिर चर लोड नहीं किया गया था, तो कई एक साथ अनुरोध त्रुटि दस्तावेज़ को अलग से लोड करना शुरू कर देते थे। केवल एक शब्दकोश जीत जाएगा और स्थैतिक चर में सहेजा जाएगा। हालांकि, अगर त्रुटि फ़ाइल बड़ी है, तो इसे एक साथ लोड करने वाले एकाधिक थ्रेड मेमोरी दबाव में वृद्धि करेंगे। यदि यह मामला था, तो मुझे उम्मीद है कि अगले कचरा संग्रह अतिरिक्त उदाहरणों को पुनः प्राप्त करेगा और इस मेमोरी को छोड़ देगा।

यह भी ध्यान दें कि स्थिर उदाहरण संस्करण एक बार त्रुटि फ़ाइल लोड करता है। इसलिए यदि अतिरिक्त त्रुटियां बनाई गईं, तो ये कभी क्लाइंट को वापस नहीं लौटाई जाएंगी।

+0

हां, चूंकि कोई भी सिंक्रनाइज़ेशन नहीं है, इसलिए GetErrorData कॉल सभी को एचटीपी कैश में अपना उदाहरण जोड़ देगा, इस प्रकार एक्सएमएल डेटा की कई समान प्रतियां स्मृति में संग्रहीत की जा सकती हैं। – Mahol25

0

अपनी डब्ल्यू 3 पी प्रक्रिया का डंप लेने की कोशिश करें और बड़ी ऑब्जेक्ट ढेर पर क्या है और कौन सी वस्तुएं स्मृति के बड़े हिस्से पर कब्जा कर रही हैं। इससे आपको स्मृति रिसाव के सटीक कारण तक पहुंचने में मदद मिलेगी।

आपको स्मृति में लोड असेंबली भी जांचनी चाहिए। XMLserializers उदाहरणों में से एक है।

मेमोरी लीक पर टेस के ब्लॉग का संदर्भ लें। http://blogs.msdn.com/b/tess/archive/2008/03/17/net-debugging-demos-lab-6-memory-leak.aspx

0

सिंक्रनाइज़ेशन जोड़ने से आपकी "मेमोरी लीक" ठीक हो जाती है?

यही कारण है, उदाहरण के लिए LoadXmlDocument() और GetErrorData() दोनों निजी बनाने के लिए और इस तरह

private static Dictionary<string, ErrorData> _errorData; 
    private static object lockObject = new object(); 

    internal static Dictionary<string, ErrorData> ErrorData 
    { 
     get 
     { 
      lock (lockObject) 
      { 
       if (_errorData == null) 
       { 
        _errorData = GetErrorData(); 
       } 
       return _errorData; 
      } 
     } 

    } 

नोट ErrorData संपत्ति कुछ संशोधित: आमतौर पर, एक स्मृति रिसाव का मतलब है कि आवेदन धीरे-धीरे समय के साथ अधिक उपभोग और अधिक स्मृति (जिसे कभी पुनः प्राप्त नहीं किया जाता है)। क्या आप यह देख रहे हैं, या जब आप कार्यान्वयन को बदलते हैं तो आपकी स्मृति खपत स्थिर हो जाती है? वास्तव में यह सत्यापित करने के लिए कि आपके पास वास्तव में एक स्मृति रिसाव है और वास्तविक कारण क्या है (कौन सी वस्तुओं को एकत्र/अंतिम रूप नहीं दिया जा सकता है), आपको अक्सर मेमोरी प्रोफाइलर का उपयोग करना होगा।

संबंधित मुद्दे