2011-10-04 15 views
13

में क्या जाना चाहिए मैं Winforms अनुप्रयोग में कुछ मेमोरी लीक मुद्दों को ठीक कर रहा हूं और कुछ डिस्पोजेबल ऑब्जेक्ट्स को देखा है जो स्पष्ट रूप से विस्थापित नहीं हैं (डेवलपर ने निपटान विधि नहीं कहा है)। अंतिमकरण विधि का कार्यान्वयन भी मदद नहीं करता है क्योंकि यह if (disposing) खंड में नहीं जाता है। सभी स्थैतिक कार्यक्रम अनियंत्रण और संग्रह समाशोधन को if (disposing) खंड में रखा गया है। सबसे अच्छा अभ्यास निपटान को बुला रहा है अगर ऑब्जेक्ट डिस्पोजेबल है, लेकिन दुर्भाग्य से यह कभी-कभी होता हैआईडीस्पोजेबल कार्यान्वयन - 'अगर (निपटान)'

यदि अप्रबंधित ऑब्जेक्ट्स, स्थैतिक ईवेंट हैंडलर और कुछ प्रबंधित संग्रह जिन्हें डिस्पोजेक्ट करते समय साफ़ करने की आवश्यकता होती है। यह तय करने का तरीका क्या है कि if (disposing) खंड में क्या जाना चाहिए और क्या जाना चाहिए।

Dispose method.

// Dispose(bool disposing) executes in two distinct scenarios. 
// If disposing equals true, the method has been called directly 
// or indirectly by a user's code. Managed and unmanaged resources 
// can be disposed. 
// If disposing equals false, the method has been called by the 
// runtime from inside the finalizer and you should not reference 
// other objects. Only unmanaged resources can be disposed. 
protected virtual void Dispose(bool disposing) 
{ 
    if (!disposed) 
    { 
     if (disposing) 
     { 
      // Free other state (managed objects). 
     } 

     // Free your own state (unmanaged objects). 
     // Set large fields to null. 
     disposed = true; 
    } 
} 

It says प्रबंधित वस्तुओं जो आम तौर पर केवल कार्यान्वित जब स्पष्ट रूप से डेवलपर द्वारा निपटान विधि कॉल if (disposing) में करना चाहिए। यदि अंतिम विधि लागू की गई है और डेवलपर निपटान विधि को कॉल करने के लिए भूल जाता है तो अंतिमकरण के माध्यम से यहां आने वाले निष्पादन if (disposing) अनुभाग में नहीं जाते हैं।

नीचे मेरे प्रश्न हैं।

  1. यदि मेरे पास स्थिर घटना हैंडलर हैं जो मेमोरी लीक का कारण बनता है तो मुझे उन्हें पंजीकृत क्यों करना चाहिए? if (disposing) खंड में या बाहर?

  2. यदि मेरे पास कुछ संग्रह हैं जो मेमोरी लीक का कारण बनते हैं तो मुझे उन्हें साफ़ करना चाहिए? if (disposing) खंड में या बाहर?

  3. यदि मैं तृतीय पक्ष डिस्पोजेबल ऑब्जेक्ट्स (उदाहरण: devExpress Winform नियंत्रण) का उपयोग कर रहा हूं, तो मुझे यकीन नहीं है कि वे प्रबंधित या अप्रबंधित ऑब्जेक्ट्स हैं या नहीं। मान लें कि मैं एक फॉर्म का निपटान करते समय उन्हें निपटाना चाहता हूं। मैं कैसे जान सकता हूं कि प्रबंधित क्या हैं और गैर-प्रबंधित वस्तुओं क्या हैं? डिस्पोजेबल होने के नाते यह नहीं कहता है? ऐसे मामलों में यह तय करने के लिए कि क्या जाना चाहिए और if (disposing) खंड से क्या बाहर जाना चाहिए?

  4. यदि मुझे यकीन नहीं है कि कुछ प्रबंधित या अप्रबंधित है तो if (disposing) खंड से बाहर निकालने/समाशोधन/अनियंत्रित घटनाओं के खराब परिणाम क्या हो सकते हैं? मान लीजिए कि यह निपटान से पहले शून्य के लिए जाँच करता है?

संपादित

क्या मैं घटना संयुक्त राष्ट्र से पंजीकृत कराने के रूप में मतलब नीचे की तरह कुछ है। प्रकाशक एक लंबे समय तक रहने वाला उदाहरण है और नीचे की रेखा ग्राहक के निर्माता में है। इस मामले में ग्राहक को घटना को अपंजीकृत करने और प्रकाशक के सामने निपटान करने की आवश्यकता है।

publisher.DoSomeEvent += subscriber.DoSomething; 

उत्तर

0

क्या में जाना चाहिए 'अगर (निपटान)'

सभी प्रबंधित वस्तुओं अंदर अगर (निपटान) खंड जाना चाहिए। प्रबंधित वस्तुओं को इसके बाहर नहीं जाना चाहिए (जिसे अंतिम रूप से निष्पादित किया जाएगा)।

कारण यह है कि कचरा कलेक्टरों की अंतिम प्रक्रिया प्रक्रिया निपटान (झूठी) को निष्पादित कर सकती है यदि उस वर्ग में विनाशक है। आम तौर पर अगर कोई अप्रबंधित संसाधन नहीं होता है तो केवल एक विनाशक होता है। गैरेज कलेक्टर के अंतिमकरण में अंतिमकरण विधि निष्पादित करने के लिए कोई विशेष आदेश नहीं होता है। इसलिए, अन्य प्रबंधित ऑब्जेक्ट्स समय समाप्ति के समय स्मृति में नहीं हो सकते हैं।

0

तो मुझे लगता है कि मेमोरी लीक का कारण बनता है स्थिर ईवेंट हैंडलर्स है जहां मैं उन्हें संयुक्त राष्ट्र से रजिस्टर करना चाहिए? अगर (निपटान) खंड में या बाहर?

निपटान विधि उन उदाहरणों पर बुलाया जाता है जहां स्थिर स्तर हैंडलर कक्षा स्तर पर उपयोग किया जाता है। तो आपको निपटान में उन्हें बिल्कुल पंजीकृत नहीं करना चाहिए। आम तौर पर स्टैटिक इवेंट हैंडलर अन-रजिस्टर होना चाहिए जब कक्षा अनलोड हो या आवेदन के निष्पादन के दौरान किसी बिंदु पर आपको यह पता चलता है कि इस ईवेंट हैंडलर की आवश्यकता नहीं है।

सभी प्रबंधन और अन-प्रबंधित संसाधनों के लिए बेहतर ढंग से IDISposable पैटर्न लागू करें। यहाँ देखें http://msdn.microsoft.com/en-us/library/fs2xkftw%28VS.80%29.aspx और Finalize/Dispose pattern in C#

+0

स्थिर घटनाओं की सदस्यता लेने के उदाहरणों के लिए यह बिल्कुल असामान्य नहीं है। ऐसे मामलों को अगर (निपटान) खंड के भीतर सदस्यता समाप्त करनी चाहिए। – supercat

2

मोटे तौर पर, प्रबंधित संसाधनों इसके बाहर if (disposing) और अप्रबंधित संसाधनों के अंदर निपटारा कर रहे हैं। निपटाने प्रतिमान में काम करता है: इस वस्तु को पहले से ही निपटान किया जाता है

  1. if (disposed) {

    हैं, तो दूसरी बार से नष्ट नहीं है।

  2. if (disposing) {

    तो निपटान प्रोग्राम के (true) अनुरोध किया गया था, प्रबंधित संसाधनों (IDisposable वस्तुओं) इस वस्तु के स्वामित्व के निपटान के।

    यदि कचरा कचरा (false) के कारण होता है, तो प्रबंधित संसाधनों का निपटान न करें क्योंकि कचरा कलेक्टर पहले से ही स्वामित्व वाले प्रबंधित संसाधनों का निपटारा कर सकता है, और आवेदन समाप्त होने से पहले निश्चित रूप से उनका निपटान करेगा।

  3. }

    अप्रबंधित संसाधनों के निपटान और उन्हें सभी संदर्भों को जारी

    । चरण 1 सुनिश्चित करता है कि यह केवल एक बार होता है।

  4. disposed = true

    करें इस वस्तु के रूप में दोहराया निपटान को रोकने के लिए निपटाया। बार-बार निपटान चरण 2 या 3.

प्रश्न 1
बिल्कुल Dispose विधि में उनमें से निपटाने मत पर एक NullReferenceException हो सकती है। यदि आप कक्षा के कई उदाहरणों का निपटारा करते हैं तो क्या होगा? आप पहले से ही निपटान किए जाने के बावजूद, हर बार स्थिर सदस्यों का निपटान करेंगे। मैंने पाया समाधान AppDomain.DomainUnloaded घटना को संभालना था और वहां स्थिर निपटान करना था।

प्रश्न 2
यह सब निर्भर करता है कि संग्रह की वस्तुओं में कामयाब रहे या अप्रबंधित कर रहे हैं। यह संभवतः प्रबंधित रैपर बनाने के लायक है जो आपके द्वारा उपयोग किए जा रहे किसी भी अप्रबंधित वर्गों के लिए IDISposable लागू करते हैं, यह सुनिश्चित करने के लिए कि सभी ऑब्जेक्ट प्रबंधित हैं।

प्रश्न 3
आईडीस्पोजेबल एक प्रबंधित इंटरफ़ेस है। यदि कोई वर्ग IDISposable लागू करता है, तो यह एक प्रबंधित कक्षा है। if (disposing) के अंदर प्रबंधित वस्तुओं का निपटान करें। यदि यह IDISposable लागू नहीं करता है, तो यह या तो प्रबंधित होता है और इसे निपटान की आवश्यकता नहीं होती है, या अप्रबंधित है और इसे if (disposing) के बाहर निपटाया जाना चाहिए।

प्रश्न 4
आवेदन अप्रत्याशित रूप से समाप्त हो जाता है, या मैनुअल निपटान का उपयोग नहीं करता है, कचरा कलेक्टर यादृच्छिक क्रम में सभी वस्तुओं की disposes।बच्चे के ऑब्जेक्ट का निपटारा करने से पहले बच्चे के ऑब्जेक्ट का निपटारा किया जा सकता है, जिससे बच्चे को माता-पिता द्वारा दूसरी बार निपटान किया जा सकता है। अधिकतर प्रबंधित वस्तुओं को सुरक्षित रूप से कई बार निपटाया जा सकता है, लेकिन केवल तभी जब वे सही तरीके से बनाए गए हों। यदि आप ऑब्जेक्ट को कई बार निपटाया जाता है तो आप जोखिम (हालांकि, संभावना नहीं) को गर्गबे संग्रह विफल करने का जोखिम देते हैं।

+0

एक डिस्पोजेर कचरा कलेक्टर द्वारा कभी नहीं बुलाया जाएगा। कभी। सी # में एक विनाशक (ए.के.ए.ए.नेट फ़ाइनलाइज़र) है जिसे ऑब्जेक्ट कचरा इकट्ठा किया जाता है या नहीं। – Spence

+0

किसी ऑब्जेक्ट के लिए विनाशक का कार्यान्वयन वैकल्पिक है। – Spence

+0

@ स्पेस, आप सही हैं। 'अंतिमकरण' विधि (मैं वीबी का उपयोग करता हूं) वैकल्पिक है, लेकिन यदि आपके पास निपटान करने के लिए अप्रबंधित संसाधन हैं तो आवश्यक है। इसका उपयोग कचरा कलेक्टर के प्रवेश बिंदु के रूप में 'निपटान (बूलियन)' विधि के रूप में किया जाता है। –

0

ऐसा लगता है कि आपके पास मुख्य रूप से प्रबंधित ऑब्जेक्ट्स हैं, यानी ऑब्जेक्ट्स लागू करने वाली ऑब्जेक्ट्स। अप्रबंधित कोड IntPtr या हैंडल जैसी चीजें होंगी, जो आमतौर पर अप्रबंधित कोड या पी/इन्हें प्राप्त करने के लिए आमंत्रित करने का मतलब होगा।

  1. जैसा कि माहेप ने बताया, निपटान इसका मतलब नहीं है। जब किसी ऑब्जेक्ट को ईवेंट प्राप्त करने के लिए किया जाता है तो उसे स्वयं को अनियंत्रित करना चाहिए। यदि यह संभव नहीं है, तो इसके बजाय WeakReferences का उपयोग करने पर विचार करें।

  2. शायद यह तब तक निपटान में नहीं जाना चाहिए जब तक कि इन संग्रहों में ऐसी वस्तुओं को शामिल नहीं किया जाता है जिन्हें निपटान करने की आवश्यकता होती है। यदि वे डिस्पोजेबल ऑब्जेक्ट्स हैं तो इसे "डिस्पोजेक्टिंग" ब्लॉक में जाना चाहिए और आपको संग्रह में प्रत्येक आइटम पर निपटान करना चाहिए।

  3. यह IDisposable लागू करता है यदि यह

  4. प्रबंधित जब finalizer जो क्या "अगर (निपटान)" ब्लॉक साधन के बाहर किया जा रहा है द्वारा कहा जाता है आप अन्य प्रबंधित कोड वस्तुओं का उपयोग नहीं करना चाहिए।

3

यहां याद रखने की कुंजी IDisposable का उद्देश्य है। यह आपकी मदद है निर्धारक आपके कोड धारण करने वाले संसाधनों को से पहले ऑब्जेक्ट कचरा एकत्रित करने में आपकी सहायता करना है। यही कारण है कि सी # भाषा टीम ने कीवर्ड using चुना है, क्योंकि ब्रैकेट उस स्कोप को निर्धारित करते हैं जिस पर ऑब्जेक्ट और उसके संसाधनों को एप्लिकेशन द्वारा आवश्यक है।

उदाहरण के लिए, यदि आप किसी डेटाबेस से कनेक्शन खोलते हैं, तो आप उस कनेक्शन को रिलीज़ करना चाहते हैं और अगले कचरा संग्रह की प्रतीक्षा करने के बजाय इसे समाप्त करने के बाद इसे बंद करें। यह कहां है और आप एक डिस्पोजर को क्यों लागू करते हैं।

दूसरा परिदृश्य अप्रबंधित कोड के साथ सहायता करना है। प्रभावशाली ढंग से यह ऑपरेटिंग सिस्टम में सी ++/सी एपीआई कॉल के साथ कुछ भी करने के लिए है, इस मामले में आप यह सुनिश्चित करने के लिए ज़िम्मेदार हैं कि कोड लीक नहीं हुआ है। जितना अधिक .NET को P/केवल मौजूदा Win32 API में आमंत्रित करने के लिए लिखा गया है, यह परिदृश्य काफी आम है। कोई भी ऑब्जेक्ट जो ऑपरेटिंग सिस्टम (जैसे एक म्यूटेक्स) से संसाधन को समाहित करता है, एक डिस्पोजर को सुरक्षित रूप से और निश्चित रूप से इसके संसाधनों को रिलीज़ करने की अनुमति देने के लिए लागू करेगा।

हालांकि इन एपीआई भी एक विनाशक को लागू करने के लिए, यह गारंटी देने के लिए कि यदि आप संसाधन का सही ढंग से उपयोग नहीं करते हैं तो यह ऑपरेटिंग सिस्टम द्वारा लीक नहीं किया जाएगा। जब आपका फाइनलाइज़र कहलाता है, तो आप नहीं जानते कि आप जिन अन्य ऑब्जेक्ट्स का संदर्भ दे रहे थे, वे पहले ही कचरा एकत्र कर चुके हैं या नहीं, यही कारण है कि उन पर फ़ंक्शन कॉल करना सुरक्षित नहीं है (क्योंकि वे NullReferenceException फेंक सकते हैं), केवल अप्रबंधित संदर्भ (जो परिभाषा के अनुसार एकत्रित कचरा नहीं हो सकता है) अंतिम रूप में उपलब्ध होगा।

उम्मीद है कि थोड़ा सा मदद करता है।

+0

चीयर्स। मेरा जवाब अपडेट किया गया। – Spence

0

जब तक किसी वर्ग का एकमात्र उद्देश्य कुछ संसाधन (*) को समाहित नहीं किया जाता है, जिसे छोड़ा जाने पर साफ किया जाना चाहिए, तो उसे अंतिम रूप नहीं होना चाहिए, और निपटान (बूल) को गलत के मूल्य से कभी नहीं बुलाया जाना चाहिए , लेकिन निपटान (झूठी) को कोई प्रभाव नहीं होना चाहिए।यदि विरासत वाले वर्ग को छोड़ने पर क्लीनअप की आवश्यकता वाले संसाधन को पकड़ने की आवश्यकता होगी, तो उसे उस उद्देश्य को उस उद्देश्य के लिए समर्पित वस्तु में समाहित करना चाहिए। इस तरह, यदि मुख्य वस्तु को त्याग दिया जाता है और कोई भी संसाधन संसाधन को समाहित करने वाले ऑब्जेक्ट का कोई संदर्भ नहीं रखता है, तो वह वस्तु अतिरिक्त जीसी चक्र के लिए मुख्य वस्तु को जीवित रखने के बिना अपने सफाई को निष्पादित कर सकती है।

संयोग से, मैं विस्थापित ध्वज के माइक्रोसॉफ्ट के हैंडलिंग को नापसंद करता हूं। मैं सुझाव दूंगा कि गैर-आभासी निपटान विधि को इंटरलॉक.एक्सचेंज के साथ एक पूर्णांक ध्वज का उपयोग करना चाहिए, यह सुनिश्चित करने के लिए कि एकाधिक थ्रेड से निपटने का निर्णय केवल एक बार तर्क को निष्पादित किया जा रहा है। ध्वज स्वयं निजी हो सकता है, लेकिन प्रत्येक व्युत्पन्न कक्षा को अपने निपटान ध्वज को लागू करने के लिए आवश्यक से बचने के लिए एक संरक्षित और/या सार्वजनिक विस्थापित संपत्ति होनी चाहिए।

(*) एक संसाधन कुछ विशेष प्रकार की इकाई नहीं है, बल्कि एक ढीली अवधि है जिसमें किसी भी वर्ग को शामिल किया गया हो सकता है, कुछ बाहरी इकाई को इसकी ओर से करने के लिए कहा जा सकता है, जिसे बाहरी इकाई को रोकने के लिए कहा जाना चाहिए करते हुए। सबसे आम तौर पर, बाहरी इकाई ने कक्षा का विशेष उपयोग कुछ किया होगा (चाहे वह स्मृति का क्षेत्र हो, एक ताला, एक जीडीआई हैंडल, एक फ़ाइल, एक सॉकेट, एक यूएसबी डिवाइस, या जो भी हो), लेकिन कुछ मामलों में बाहर इकाई को कुछ करने के लिए सकारात्मक रूप से कुछ करने के लिए कहा जा सकता है (उदाहरण के लिए हर बार कुछ घटना होने पर एक ईवेंट हैंडलर चलाएं) या कुछ पकड़ें (जैसे थ्रेड-स्टेटिक ऑब्जेक्ट रेफरेंस)। एक "अप्रबंधित" संसाधन वह है जिसे छोड़ा जाने पर साफ नहीं किया जाएगा।

बीटीडब्लू, ध्यान दें कि माइक्रोसॉफ्ट का इरादा हो सकता है कि अप्रबंधित संसाधनों को समाहित करने वाले ऑब्जेक्ट्स को छोड़कर उन्हें साफ कर देना चाहिए, ऐसे कुछ प्रकार के संसाधन हैं जिनके लिए वास्तव में व्यावहारिक नहीं है। किसी ऑब्जेक्ट पर विचार करें जो किसी ऑब्जेक्ट संदर्भ को थ्रेड-स्टेटिक फ़ील्ड में संग्रहीत करता है, उदाहरण के लिए, और उस ऑब्जेक्ट संदर्भ को डिस्पोजेड होने पर रिक्त करता है (निपटान, स्वाभाविक रूप से, उस थ्रेड पर होना चाहिए जहां ऑब्जेक्ट बनाया गया था)। यदि ऑब्जेक्ट छोड़ दिया जाता है लेकिन धागा अभी भी मौजूद है (उदा। थ्रेडपूल में), थ्रेड-स्टेटिक संदर्भ का लक्ष्य आसानी से अनिश्चित काल तक जीवित रखा जा सकता है। यहां तक ​​कि अगर त्याग किए गए ऑब्जेक्ट का कोई संदर्भ नहीं है, तो इसकी अंतिम() विधि चलती है, तो छोड़े गए ऑब्जेक्ट को कुछ धागे में बैठे धागे-स्थैतिक संदर्भ को ढूंढने और नष्ट करने में मुश्किल होगी।

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

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