33

मैं विंडोज़ फॉर्म एप्लिकेशन में मेमोरी रिसाव को चलाने की कोशिश कर रहा हूं। मैं अब एक ऐसे फॉर्म में देख रहा हूं जिसमें कई एम्बेडेड फॉर्म हैं। मुझे चिंता है कि बच्चे अपने रचनाकार में, माता-पिता के रूप में संदर्भ लेते हैं, और इसे एक निजी सदस्य क्षेत्र में रखते हैं। तो मुझे ऐसा लगता है कि कचरा-संग्रहण समय आ गया:परिपत्र संदर्भ मेमोरी लीक का कारण बनता है?

माता-पिता के नियंत्रण संग्रह के माध्यम से बच्चे के रूप में संदर्भ है (बाल रूप वहां एम्बेडेड है)। बाल फार्म जीसी'd नहीं है।

बाल फार्म का निजी सदस्य फ़ील्ड के माध्यम से मूल रूप से संदर्भ है। अभिभावक रूप जीसी'd नहीं है।

क्या यह सही समझ है कि कचरा कलेक्टर स्थिति का मूल्यांकन कैसे करेगा? परीक्षण प्रयोजनों के लिए इसे साबित करने का कोई तरीका?

उत्तर

36

शानदार सवाल!

नहीं, दोनों फॉर्म जीसीएडी (हो सकते हैं) होंगे क्योंकि जीसी सीधे अन्य संदर्भों में संदर्भों की तलाश नहीं करता है। यह केवल "रूट" संदर्भ कहलाता है ... इसमें स्टैक पर संदर्भ चर शामिल हैं, (वैरिएबल स्टैक पर है, वास्तविक वस्तु ढेर पर है), सीपीयू रजिस्टरों में संदर्भ चर, और संदर्भ चर कक्षाओं में स्थिर क्षेत्र ...

अन्य सभी संदर्भ चर केवल इन्हें एक्सेस किया जाता है (और जीसीएडी) यदि उपर्युक्त प्रक्रिया द्वारा प्राप्त "रूट" संदर्भ वस्तुओं में से किसी एक की संपत्ति में संदर्भित किया गया है ... (या रूट ऑब्जेक्ट, आदि में किसी संदर्भ द्वारा संदर्भित ऑब्जेक्ट में ...)

तो केवल अगर किसी एक रूप को "रूट" संदर्भ में कहीं और संदर्भित किया गया है - तो दोनों रूप जीसी से सुरक्षित होंगे।

एकमात्र तरीका मैं इसे "साबित" करने के बारे में सोच सकता हूं, (मेमोरी ट्रेस यूटिलिटीज का उपयोग किए बिना) एक विधि के अंदर एक लूप में, इन सौ रूपों में से कुछ हज़ारों का निर्माण करना होगा, फिर विधि में, देखें ऐप की मेमोरी पदचिह्न, फिर विधि से बाहर निकलें, जीसी को कॉल करें, और फिर पदचिह्न को देखें।

+2

या बस प्रत्येक प्रपत्र के अंदर एक बड़े पैमाने पर बफर आवंटित। – Gusdor

5

यदि दोनों माता-पिता और बच्चे का संदर्भ नहीं दिया जाता है, लेकिन वे केवल एक दूसरे का संदर्भ देते हैं, तो उन्हें जीसीड मिलता है।

वास्तव में अपने एप्लिकेशन की जांच करने और अपने सभी सवालों के जवाब देने के लिए एक मेमोरी प्रोफाइलर प्राप्त करें। मैं http://memprofiler.com/

0

जीसी परिपत्र संदर्भों के साथ सही ढंग से सौदा कर सकता है और यदि ये संदर्भ केवल जीवित रखने वाले एकमात्र चीजें हैं तो उन्हें एकत्रित किया जाएगा।
मुझे फॉर्म से मेमोरी पुनः प्राप्त नहीं करने के साथ बहुत सारी परेशानी हुई है। 1.1 में कुछ बग्स aroung menuitem (मुझे लगता है) था जिसका मतलब था कि वे निपटान नहीं किया था और स्मृति रिसाव कर सकता था। इस मामले में, सदस्य के निपटान विधि में सदस्य चर को निपटाने और साफ़ करने के लिए एक स्पष्ट कॉल जोड़ना समस्या को हल करता है। हमने पाया कि इससे कुछ अन्य नियंत्रण प्रकारों के लिए स्मृति पुनः प्राप्त करने में भी मदद मिली है।
मैंने सीएलआर प्रोफाइलर के साथ एक लंबा समय बिताया कि क्यों फॉर्म नहीं एकत्र किए जा रहे थे। जहां तक ​​मैं कह सकता था, फ्रेमवर्क द्वारा संदर्भ रखा जा रहा था। एक प्रति प्रकार का प्रकार। इसलिए यदि आप फॉर्म 1 के 100 उदाहरण बनाते हैं, तो उन्हें सभी बंद करें, केवल 99 को ठीक से पुनः दावा किया जाएगा। मुझे इसका इलाज करने का कोई रास्ता नहीं मिला।
हमारे आवेदन के बाद से .NET 2 में स्थानांतरित हो गया है और यह बहुत बेहतर प्रतीत होता है। जब हम पहले फॉर्म खोलते हैं तो हमारी एप्लिकेशन मेमोरी अभी भी बढ़ जाती है और बंद होने पर वापस नहीं जाती है, लेकिन मेरा मानना ​​है कि यह जेआईटी कोड और अतिरिक्त नियंत्रण पुस्तकालयों के कारण है जो लोड हो गए हैं।
मुझे यह भी पता चला है कि हालांकि जीसी परिपत्र संदर्भों से निपट सकता है, हालांकि सर्कुलर इवेंट हैंडलर संदर्भों के साथ समस्याएं (कभी-कभी) होती हैं।आईई ऑब्जेक्ट 1 संदर्भ ऑब्जेक्ट 2 और ऑब्जेक्ट 1 में एक विधि है जो ऑब्जेक्ट 2 से हैंडल और इवेंट। मुझे परिस्थितियां मिलीं, जहां मैंने अपेक्षा की थी कि ऑब्जेक्ट्स को रिलीज़ नहीं किया गया था, लेकिन मैं टेस्ट केस में इसे फिर से उत्पादित करने में सक्षम नहीं था।

16

के रूप में दूसरों को पहले से ही कहा है, जीसी वृत्तीय संदर्भ के साथ कोई समस्या नहीं है। मैं बस जोड़ना चाहता हूं, .NET में स्मृति को रिसाव करने के लिए एक आम जगह ईवेंट हैंडलर हैं। यदि आपके किसी एक फॉर्म में एक अटैचमेंट इवेंट हैंडलर है जो "ऑब्जेक्ट" है, तो आपके फॉर्म का संदर्भ है और फॉर्म जीसीडी नहीं मिलेगा।

+2

एक उत्तर जो आपके उदाहरण का वर्णन करता है: http://stackoverflow.com/a/12133788/6345 –

12

कचरा संग्रह आवेदन जड़ों को ट्रैक करके काम करता है। एप्लिकेशन जड़ें भंडारण स्थान हैं जिनमें प्रबंधित ढेर (या शून्य) पर ऑब्जेक्ट्स के संदर्भ शामिल हैं। नेट में, जड़ों

  1. वैश्विक वस्तुओं के सन्दर्भ
  2. संदर्भ स्थिर वस्तुओं के लिए
  3. स्थिर क्षेत्रों स्थानीय वस्तुओं के लिए ढेर पर
  4. संदर्भ के संदर्भ हैं ढेर मापदंडों आपत्ति उठाने पर
  5. संदर्भ विधियों को पास किया गया
  6. ऑब्जेक्ट्स के संदर्भ अंतिम रूप देने के लिए प्रतीक्षा कर रहे हैं
  7. प्रबंधित किए गए ऑब्जेक्ट्स पर CPU रजिस्टरों में संदर्भ एपी

सक्रिय जड़ों की सूची CLR द्वारा बनाए रखा है। कचरा कलेक्टर प्रबंधित ढेर पर ऑब्जेक्ट्स को देखकर काम करता है और देख रहा है जो एप्लिकेशन द्वारा अभी भी सुलभ है, यानी, एप्लिकेशन रूट के माध्यम से सुलभ है। इस तरह की एक वस्तु को जड़ माना जाता है।

अब मान लीजिए कि आप एक माता पिता के फार्म का है कि बच्चे के रूपों और इन बच्चे रूपों माता पिता रूप के संदर्भ हो के लिए संदर्भ शामिल है। इसके अलावा, मान लें कि एप्लिकेशन में माता-पिता के लिए या किसी भी बच्चे के रूप में कोई संदर्भ नहीं है। फिर, कचरा कलेक्टर के प्रयोजनों के लिए, इन प्रबंधित वस्तुओं को अब रूट नहीं किया गया है और अगली बार एक कचरा संग्रह होता है जब कचरा इकट्ठा किया जाएगा।

+0

@ जेसन, "ऑब्जेक्ट पैरामीटर" से आपका क्या मतलब है? और मुझे विश्वास है संदर्भ का स्थान महत्वपूर्ण निर्धारक है ... ढेर, या एक वर्ग का एक स्थिर सदस्य, या एक सीपीयू रजिस्टर में पर है, तो यह एक रूट संदर्भ है तो। ... अन्यथा नहीं। (freachable कतार को छोड़कर, - एक और विषय) –

2

मैं घटनाओं के बारे में Vilx की टिप्पणी प्रतिध्वनित करने के लिए, और एक डिजाइन पैटर्न यह संबोधित मदद करता है कि सिफारिश करने के लिए करना चाहते हैं।

मान लीजिए कि आप एक प्रकार की एक घटना स्रोत है, उदा .:

interface IEventSource 
{ 
    event EventHandler SomethingHappened; 
} 

यहां कक्षा कि उस प्रकार के उदाहरणों से घटनाओं हैंडल का एक टुकड़ा है कि करते हैं। विचार यह है कि जब भी आप संपत्ति के लिए एक नया उदाहरण आवंटित करते हैं, तो आप पहले किसी भी पिछले असाइनमेंट से सदस्यता छोड़ते हैं, फिर नए इंस्टेंस की सदस्यता लेते हैं। शून्य जांच सही सीमा व्यवहार सुनिश्चित करती है, और बिंदु पर अधिक, निपटान को सरल बनाते हैं: आप जो भी करते हैं वह संपत्ति को शून्य करता है।

जो निपटान का मुद्दा लाता है। किसी भी वर्ग जो घटनाओं की सदस्यता लेता है उसे IDISposable इंटरफेस को कार्यान्वित करना चाहिए क्योंकि ईवेंट प्रबंधित संसाधन हैं। (N.B. मैं संक्षिप्तता की खातिर उदाहरण में निपटान पैटर्न के एक उचित कार्यान्वयन को छोड़ दिया है, लेकिन आप विचार मिलता है।)

class MyClass : IDisposable 
{ 
    IEventSource m_EventSource; 
    public IEventSource EventSource 
    { 
     get { return m_EventSource; } 
     set 
     { 
      if(null != m_EventSource) 
      { 
       m_EventSource -= HandleSomethingHappened; 
      } 
      m_EventSource = value; 
      if(null != m_EventSource) 
      { 
       m_EventSource += HandleSomethingHappened; 
      } 
     } 
    } 

    public Dispose() 
    { 
     EventSource = null; 
    } 

    // ... 
} 
संबंधित मुद्दे