2013-06-18 10 views
8

होने से कचरा कलेक्टर को रोकने मैं कोडक्यों ईवेंट हैंडलर्स

public class Publisher 
{ 
    public event EventHandler SomeEvent; 
} 

public class Subscriber 
{ 
    public static int Count; 

    public Subscriber(Publisher publisher) 
    { 
     publisher.SomeEvent += new EventHandler(publisher_SomeEvent); 
    } 

    ~Subscriber() 
    { 
     Subscriber.Count++; 
    } 

    private void publisher_SomeEvent(object sender, EventArgs e) 
    { 
     // TODO 
    } 
} 

के इस टुकड़े अपने आवेदन की मुख्य विधि में है मैं

static void Main(string[] args) 
{ 
    Publisher publisher = new Publisher(); 

    for (int i = 0; i < 10; i++) 
    { 
     Subscriber subscriber = new Subscriber(publisher); 
     subscriber = null; 
    } 

    GC.Collect(); 
    GC.WaitForPendingFinalizers(); 

    Console.WriteLine(Subscriber.Count.ToString()); 
} 

है, तो मैं इस चलाने के लिए, मैं के रूप में 0 होगा उत्पादन। जो 10

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

तो मैं 2 सवाल

  1. मेरी धारणा सही और घटना सदस्यता जीसी ग्राहक उदाहरणों चिह्नित करने के लिए एकत्र होने के लिए रोकता है?
  2. यदि ऐसा है, तो ऐसा इसलिए है क्योंकि प्रकाशक को ग्राहक का संदर्भ है? (Garbage collector and event handlers)

मेरी केवल अनुमान के बाद से वहाँ सब्सक्राइबर के 10 उदाहरणों कि एक ही प्रकाशक उदाहरण के लिए संदर्भित कर रहे हैं कर रहे हैं, जब जी सी संग्रह होता है, यह देखता है कि वहाँ, प्रकाशक को अन्य संदर्भ हैं कि इस प्रकार यह नहीं कर सकता है एकत्रित किया जाए, और नतीजतन प्रकाशक के साथ सभी सब्सक्रिप्शन उदाहरण अगली पीढ़ी में स्थानांतरित किए जा रहे हैं, इसलिए कचरा संग्रह नहीं होता है और न ही अंतिमकरण() को कोड निष्पादन कंसोल पर पहुंचा जा रहा है। साइटलाइन (सब्सक्राइबर .Count.ToString())

क्या मैं सही हूं या क्या मुझे यहां कुछ याद आ रही है?

+1

इस तरह से इसके बारे में सोचो: जब 'Publisher.SomeEvent' प्रतिनिधि बुलाया जा रहा है यह निष्पादित करेंगे जो कुछ भी कॉल के समय यह करने के लिए सदस्यता लिया है। इसका मतलब यह है कि सदस्यता सक्रिय होने पर ग्राहक उदाहरण जीवित रहना पड़ता है। यही कारण है कि प्रकाशक को सभी ग्राहकों का संदर्भ रखना है। चूंकि ग्राहक पहुंच योग्य हैं जीसी उन्हें एकत्र नहीं कर सकते हैं। –

उत्तर

4

आप गलत पहचान कर रहे हैं कि वास्तव में क्या चल रहा है, सी # में एक बहुत आम जाल है। आपको अपने टेस्ट प्रोग्राम के रिलीज बिल्ड को चलाने और डीबगर के बिना इसे चलाने की आवश्यकता होगी (Ctrl + F5 दबाएं)। जिस तरह से यह आपके उपयोगकर्ता की मशीन पर चल जाएगा। और अब लगता है कि यह पूरी तरह से अब और क्या है या नहीं आप घटना सदस्यता ले कोई फर्क नहीं पड़ता, आप हमेशा से 10

मिल जाएगा मुद्दा है कि, जब आप एक डिबगर का उपयोग करें, प्रकाशक वस्तु एकत्र नहीं प्राप्त करता है । मैंने this answer में विस्तार से इसका कारण बताया।

उस पर थोड़ा विस्तार करते हुए, आपके पास परिपत्र संदर्भ हैं। सब्सक्राइबर ऑब्जेक्ट्स प्रकाशक ऑब्जेक्ट का संदर्भ देता है। और प्रकाशक ऑब्जेक्ट में सब्सक्राइबर ऑब्जेक्ट्स के संदर्भ हैं।परिपत्र संदर्भ वस्तुओं को जीवित रखने के लिए पर्याप्त नहीं हैं। और इसके लिए भलाई का शुक्र है, अगर मामला था तो कचरा संग्रह बहुत प्रभावी नहीं होगा। प्रकाशक ऑब्जेक्ट जीवित रहने के लिए कहीं और संदर्भित किया जाना चाहिए, स्थानीय चर पर्याप्त नहीं है।

+0

उत्तर के लिए धन्यवाद! वास्तव में आउटपुट 10 है जब मैं ctrl + f5 को मारकर रिलीज बिल्ड चला रहा हूं। – Michael

+0

"सब्सक्राइबर ऑब्जेक्ट्स प्रकाशक ऑब्जेक्ट का संदर्भ देता है।" वास्तव में? – Henrik

+0

मुझे लगता है कि इसका मतलब यह होगा कि जब तक प्रकाशक वस्तु का संदर्भ जारी रखा जाता है, तब तक ग्राहकों को जीवित रखने की गारंटी बहुत अधिक है? – Panzercrisis

3

दोनों प्रश्नों का उत्तर हाँ है।

+0

कथित तौर पर धन्यवाद, क्या आपको लगता है कि अंतिम अनुच्छेद में धारणा भी सही है? – Michael

+0

@michaelmoore ग्राहकों को प्रकाशक के संदर्भ नहीं हैं। यह 'मुख्य' में स्थानीय चर 'प्रकाशक' है जो 'प्रकाशक' उदाहरण को रोकता है और बदले में 10 'सब्सक्राइबर' उदाहरण एकत्र होने से रोकता है। – Henrik

+2

आपने समझाया नहीं है कि क्यों * प्रकाशक * एकत्र नहीं हो रहा है। यह * एकत्र हो रहा है, सिर्फ तब नहीं जब ओपी ने अपना कोड चलाने की कोशिश की। –

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