2013-01-20 69 views
5

मैं यह समझने की कोशिश कर रहा हूं कि ईवेंट मेमोरी रिसाव कैसे कर सकता है। मुझे this स्टैक ओवरफ्लो प्रश्न पर एक अच्छी व्याख्या मिली लेकिन विंडग में ऑब्जेक्ट्स को देखते समय, मुझे परिणाम से भ्रमित हो रहा है। शुरू करने के लिए, मेरे पास निम्नानुसार एक साधारण वर्ग है।जब ईवेंट की सदस्यता समाप्त नहीं होती है तो यह स्मृति रिसाव का कारण नहीं बनता है

class Person 
    { 
     public string LastName { get; set; } 
     public string FirstName { get; set; } 

     public event EventHandler UponWakingUp; 
     public Person() { } 

     public void Wakeup() 
     { 
      Console.WriteLine("Waking up"); 
      if (UponWakingUp != null) 
       UponWakingUp(null, EventArgs.Empty); 
     } 
    } 

अब मैं इस वर्ग का उपयोग विंडोज़ फॉर्म एप्लिकेशन में निम्नानुसार कर रहा हूं।

public partial class Form1 : Form 
    { 
     Person John = new Person() { LastName = "Doe", FirstName = "John" }; 

     public Form1() 
     { 
      InitializeComponent(); 

      John.UponWakingUp += new EventHandler(John_UponWakingUp); 
     } 

     void John_UponWakingUp(object sender, EventArgs e) 
     { 
      Console.WriteLine("John is waking up"); 
     } 

     private void button1_Click(object sender, EventArgs e) 
     { 
      John = null; 
      GC.Collect(); 
      GC.WaitForPendingFinalizers(); 
      GC.Collect(); 
      MessageBox.Show("done"); 
     } 
    } 

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

मेरा सवाल यह है कि अगर यह स्मृति रिसाव का कारण बनता है। यदि नहीं, तो क्यों नहीं?

0:005> !do 0158d334 
Name:  WindowsFormsApplication1.Form1 
MethodTable: 00366390 
EEClass:  00361718 
Size:  332(0x14c) bytes 
File:  c:\Sandbox\\WindowsFormsApplication1\WindowsFormsApplication1\bin\Debug\WindowsFormsApplication1.exe 
Fields: 
     MT Field Offset     Type VT  Attr Value Name 
619af744 40001e0  4  System.Object 0 instance 00000000 __identity 
60fc6c58 40002c3  8 ...ponentModel.ISite 0 instance 00000000 site 
619af744 4001534  b80  System.Object 0 static 0158dad0 EVENT_MAXIMIZEDBOUNDSCHANGED 
**00366b70 4000001  13c ...plication1.Person 0 instance 00000000 John** 
60fc6c10 4000002  140 ...tModel.IContainer 0 instance 00000000 components 
6039aadc 4000003  144 ...dows.Forms.Button 0 instance 015ad06c button1 

0:008> !DumpHeap -mt 00366b70  
Address  MT  Size 
total 0 objects 
Statistics: 
     MT Count TotalSize Class Name 
Total 0 objects 

उत्तर

5

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

परिपत्र संदर्भ कुछ स्वचालित स्मृति प्रबंधन योजनाओं में विशेष रूप से संदर्भ गणना में एक समस्या हो सकती है। लेकिन .NET कचरा कलेक्टर के साथ कोई समस्या नहीं है। जब तक न तो फॉर्म ऑब्जेक्ट और न ही व्यक्ति ऑब्जेक्ट में कोई अतिरिक्त संदर्भ हो, तब तक दोनों के बीच परिपत्र संदर्भ एक दूसरे को जीवित नहीं रख सकता है।

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

तो सामान्य तरीके से यह साफ़ किया गया है कि उपयोगकर्ता ऊपरी दाएं कोने में एक्स पर क्लिक करके विंडो बंद कर देता है। जो बदले में देशी खिड़की हैंडल को नष्ट कर देता है। जो उस आंतरिक तालिका से फ़ॉर्म संदर्भ को हटा देता है। अगला कचरा संग्रह अब परिपत्र संदर्भ के अलावा कुछ भी नहीं देखता है और उन्हें दोनों एकत्र करता है।

4

जवाब सवाल का जवाब आप से जुड़ा हुआ है में वास्तव में है:

एक श्रोता एक घटना के लिए एक घटना श्रोता देता है, स्रोत वस्तु श्रोता के लिए एक संदर्भ मिल जाएगा वस्तु। इसका मतलब है कि श्रोता कचरा कलेक्टर द्वारा तक ईवेंट हैंडलर अलग नहीं किया जा सकता है, या स्रोत ऑब्जेक्ट एकत्रित किया जा सकता है।

आप स्रोत वस्तु (Person) तो श्रोता (अपने Form) जारी कर रहे हैं जिसके कारण वहाँ कोई स्मृति रिसाव है एकत्र होने के लिए ठीक है।

एक मेमोरी लीक तब होगी जब यह स्थिति आईई के आसपास दूसरी तरफ होगी। जब आप Form का निपटान करना चाहते हैं लेकिन ईवेंट स्रोत (आपकी Person ऑब्जेक्ट) अभी भी इसके संदर्भ में जीवित है।

+0

इस मामले में फॉर्म 1 स्रोत वर्ग की सूची है जो व्यक्ति वर्ग उदाहरण है। क्या आप कह रहे हैं कि जॉन के पास फॉर्म 1 का संदर्भ होगा ???? मैं अब पूरी तरह से उलझन में हूँ। –

+0

@palmsnow हाँ, 'John.UponWakingUp' में एक प्रतिनिधि का संदर्भ है जिसमें' फॉर्म 1 'का संदर्भ शामिल है। यह घटना बढ़ाना अन्यथा काम नहीं कर सका। – svick

+0

अधिक जानकारी के लिए [यह] (http://csharpindepth.com/Articles/Chapter2/Events.aspx) आलेख देखें। एक अच्छी तरह से संरचित प्रश्न के लिए बीटीडब्ल्यू +1। –

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

  • कोई संबंधित समस्या नहीं^_^