2008-08-19 20 views
19

कहें कि हमारे पास निम्न विधि है:घटना हैंडलर के रूप में लैम्बडा का उपयोग कर स्मृति रिसाव का कारण बन सकता है?

private MyObject foo = new MyObject(); 

// and later in the class 

public void PotentialMemoryLeaker(){ 
    int firedCount = 0; 
    foo.AnEvent += (o,e) => { firedCount++;Console.Write(firedCount);}; 
    foo.MethodThatFiresAnEvent(); 
} 

यदि इस विधि के साथ कक्षा को तुरंत चालू किया गया है और PotentialMemoryLeaker विधि को कई बार कहा जाता है, तो क्या हम स्मृति को रिसाव करते हैं?

क्या हम MethodThatFiresAnEvent को कॉल करने के बाद उस लैम्ब्डा ईवेंट हैंडलर को खोलने का कोई तरीका है?

+0

नीचे जवाब में संकेत के रूप में, एक संदर्भ के संरक्षण के बिना यह घृणाजनक कोई रास्ता नहीं है का उपयोग करने के बनाने के लिए। हालांकि, आप इसे अपने आप खोल सकते हैं: http://stackoverflow.com/questions/1747235/weak-event-handler-model-for-use-with-lambdas/1747236#1747236 – Benjol

उत्तर

16

हां, इसे एक चर में सहेजें और इसे अनचेक करें।

DelegateType evt = (o, e) => { firedCount++; Console.Write(firedCount); }; 
foo.AnEvent += evt; 
foo.MethodThatFiresAnEvent(); 
foo.AnEvent -= evt; 

और हाँ, यदि आप नहीं करते हैं, आप स्मृति रिसाव जाएगा, जैसा कि आप ऊपर एक नया प्रतिनिधि वस्तु हर बार हुक होगा। आप यह भी देखेंगे क्योंकि हर बार जब आप इस विधि को कॉल करते हैं, तो यह कंसोल को लाइनों की बढ़ती संख्या (केवल बढ़ती संख्या नहीं, बल्कि विधि के लिए एक कॉल के लिए विधि के लिए डंप करेगा, यह किसी भी आइटम को डंप करेगा, एक बार के लिए प्रत्येक अज्ञात विधि संलग्न)।

0

हां उसी तरह सामान्य घटना हैंडलर लीक का कारण बन सकते हैं। क्योंकि लैम्ब्डा वास्तव में करने के लिए बदल जाता है:

someobject.SomeEvent +=() => ...; 
someobject.SomeEvent += delegate() { 
    ... 
}; 

// unhook 
Action del =() => ...; 
someobject.SomeEvent += del; 
someobject.SomeEvent -= del; 

तो मूल रूप से यह है कि हम क्या 2.0 इन सभी वर्षों में उपयोग किया गया है के लिए बस थोड़ा सा कम हाथ है।

4

आप केवल स्मृति को रिसाव नहीं करेंगे, आपको अपने लैम्ब्डा को कई बार भी बुलाया जाएगा। 'PotentialMemoryLeaker' की प्रत्येक कॉल घटना सूची में लैम्ब्डा की एक और प्रतिलिपि जोड़ती है, और प्रत्येक प्रति को 'AnEvent' निकाल दिया जाता है।

1

आपका उदाहरण सिर्फ एक कंपाइलर नामित निजी आंतरिक वर्ग (फ़ील्ड फायरकाउंट और एक कंपाइलर नामित विधि के साथ) के लिए संकलित करता है। PotentialMemoryLeaker के लिए प्रत्येक कॉल क्लोजर क्लास का एक नया उदाहरण बनाता है जहां फू एक प्रतिनिधि के माध्यम से एक विधि के माध्यम से संदर्भ रखता है।

यदि आप संभावित मैमोरी लेकर के मालिक की पूरी वस्तु का संदर्भ नहीं देते हैं, तो यह सब कचरा इकट्ठा होगा।

foreach (var handler in AnEvent.GetInvocationList()) AnEvent -= handler; 
बेशक

, आप MyObject वर्ग के निजी सदस्यों के लिए उपयोग आवश्यकता होगी: अन्यथा, आप शून्य पर या इस लिख कर खाली foo के ईवेंट हैंडलर सूची foo सेट कर सकते हैं या तो।

3

वैसे आप विस्तार कर सकते हैं क्या किया गया है here प्रतिनिधियों सुरक्षित (कोई मेमोरी लीक)

+1

लिंक मर चुका है – thumbmunkeys

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