2011-01-21 14 views
5

मैं इंटरऑप का उपयोग कर .NET से COM ऑब्जेक्ट का उपयोग कर रहा हूं। ऑब्जेक्ट मूल रूप से सॉकेट से डेटा लाता है और प्रक्रिया के लिए .NET परत के लिए कुछ ईवेंट आग लगाता है। हालांकि, थोड़ी देर के बाद, COM ऑब्जेक्ट फायरिंग घटनाओं को रोकता है जो बाद में पता चला क्योंकि यह जीसी द्वारा एकत्रित किया गया है।क्या यह COM ऑब्जेक्ट कचरा संग्रह के अधीन है?

स्रोत कोड की संरचना नीचे इस एक के समान है:

static void Main(string[] args) 
{ 
    MyEventGen gen = new MyEventGen(); 
    WeakReference wr = new WeakReference(gen); 
    gen.ReceiveDataArray += 
      new _IMyEventGenEvents_ReceiveDataArrayEventHandler(gen_ReceiveDataArray); 
    while (true) 
    { 
     Thread.Sleep(1000); 
     Console.WriteLine(wr.IsAlive); 
    } 
} 

static void gen_ReceiveDataArray(ref Array indices, ref Array values) 
{ 
    // do nothing 
} 

alt text

क्या मैं अब तक पता:

  • मैं क्या समझ से, वस्तु gen shouldn किसी भी तरह से कचरा इकट्ठा नहीं किया जाएगा। चूंकि ऑब्जेक्ट Main दायरे में अभी भी सक्रिय है। लेकिन परिणाम अब तक दिखाता है कि वस्तु जीसी द्वारा एकत्र की गई थी।

  • ऑब्जेक्ट केवल कचरा-संग्रहित होता है जब डिबग किए बिना रिलीज़ और चलाया जाता है। डीबग को चलाने/डीबगर के तहत दोनों मोड चलाना ठीक है।

  • कार्यक्रम पहले जनरल # 0 संग्रह के ठीक बाद पहले "गलत" प्रिंट करेगा।

  • while लूप में ऑब्जेक्ट तक पहुंचकर, उदा। Console.WriteLine(gen.ToString()), इसे जीसीएडी होने से रोकें!

  • Program कक्षा का एक और स्थैतिक क्षेत्र जोड़कर इसके संदर्भ को जीसीएडी से भी रोकें।

  • विभिन्न लोड डेटा के साथ प्रयास करते हुए, मैंने पाया कि जीसी केवल ऑब्जेक्ट एकत्र करता है जब निजी बाइट ~ 3X एमबी की सीमा तक पहुंचते हैं।

  • CLRProfiler साथ जाँच हो रही है, का उल्लेख किया वस्तु के रूप में संदिग्ध GC'd किया गया था।

क्या मैंने कुछ महत्वपूर्ण .NET जीसी की अवधारणाओं को याद किया है? क्या GC'd होने वाली वस्तु का कारण प्राप्त करना संभव है? क्या यह संभवतः एक ज्ञात जीसी बग है?

मैं उपयोग कर रहा हूँ 2008 + .NET 3.5 SP1। अपने विचारों की सराहना करें। धन्यवाद!

उत्तर

6

इसे पुन: पेश करने के लिए COM ऑब्जेक्ट का उपयोग करने की आवश्यकता नहीं है। निम्नलिखित पर विचार करें:

public class MyEventGen 
{ 
    public event Action ReceiveDataArray; 
} 

class Program 
{ 
    public static void Main() 
    { 
     var gen = new MyEventGen(); 
     var wr = new WeakReference(gen); 
     // this is the last time we access the 
     // gen instance in this scope so after this line it 
     // is eligible for garbage collection 
     gen.ReceiveDataArray += new Action(gen_ReceiveDataArray); 

     // run the collector 
     GC.Collect(); 
     while (true) 
     { 
      Thread.Sleep(1000); 
      Console.WriteLine(wr.IsAlive); 
     } 
    } 

    static void gen_ReceiveDataArray() 
    { 
    } 
} 

इसे रिलीज़ मोड में चलाएं और यह वही व्यवहार प्रदर्शित करेगा। gen ऑब्जेक्ट दायरे से बाहर हो जाता है और कचरा इकट्ठा होता है क्योंकि लूप के निष्पादन के दौरान इसे जीवित रखने के लिए कुछ भी नहीं है।

+0

धन्यवाद डारिन! ऐसा लगता है कि मैं इन सभी वर्षों में जीसी प्रक्रिया को गलत समझाता हूं: ') – Gant

+1

@ m3rLinEz, बात यह है कि रिलीज मोड में कई अनुकूलन किए जाते हैं और जीसी वास्तव में आक्रामक हो सकता है। यह समझने में सक्षम है कि 'जीन' चर का उपयोग अब अंतिम पहुंच के बाद नहीं किया जाता है और इसे एकत्रित किया जाता है। एक स्थैतिक चर के रूप में जीन को रखने से इसे रोकने से रोका जाना चाहिए। –

2

न तो gen और न ही wr आपके while लूप के निष्पादन के दौरान मुख्य दायरे में सक्रिय रहते हैं। आप जो एक बच्चे गुंजाइश है कि पहले अपने while पाश शुरू होता है से बाहर निकल गया है वे चर डालता ब्रेसिज़ में पहली तीन पंक्तियों संलग्न।

+0

मुझे लगता है कि यह मामला नहीं है। मुझे लगता है कि ब्रेसिज़ एक टाइपो हैं, अन्यथा उनका प्रोग्राम संकलित नहीं होगा क्योंकि वह थोड़ी देर में 'wr' चर का उपयोग करने में सक्षम नहीं होंगे और गलत प्रिंट करने में सक्षम होंगे। –

+0

धन्यवाद। मैंने टाइपो को सही किया है। – Gant

+1

यहां तक ​​कि दायरे वस्तुओं को जीवित रखने के लिए पर्याप्त नहीं है: यह वह जगह है जहां वस्तुओं का उपयोग किया जाता है (हालांकि वीएस डीबगर अपने दायरे के अंत तक वस्तुओं को जीवित रखता है)। आप रिलीज बिल्ड में आश्चर्य प्राप्त कर सकते हैं जहां ऑब्जेक्ट्स को किसी विधि के बीच में एकत्र किया जाता है, या कोड की एक पंक्ति के माध्यम से भी भाग-मार्ग। –

2

आपका COM ऑब्जेक्ट जैसे ही उनके नेट समकक्ष कार्यक्रम से गायब विनाश के लिए पात्र हैं। पिछली बार gen प्रयोग किया जाता है जब ReceiveDataArray += ... कॉल किया जाता है।

आप कार्यक्रम है जहाँ यह स्वीकार्य है सफाई जगह लेने के लिए के लिए में बिंदु पर GC.KeepAlive(gen) के लिए एक कॉल जोड़ना चाहिए। वैकल्पिक रूप से, यदि प्रोग्राम बाहर निकलने तक इसे जीवित रहने की आवश्यकता है, तो आप इसे static फ़ील्ड के रूप में जोड़ सकते हैं।

+0

धन्यवाद टिम! बस पुष्टि करने के लिए, इसलिए मुझे नहीं पता कि स्थानीय चर द्वारा संदर्भित ऑब्जेक्ट अगली समाप्ति ''} 'ब्रेस तक लाइव रहेगा, जो इसके दायरे के अंत को चिह्नित करता है? – Gant

+0

यह सही है: यह किसी भी प्रबंधित कोड द्वारा सक्रिय रूप से उपयोग किए जाने तक लंबे समय तक जीवित रहेगा, लेकिन उसके बाद किसी भी समय गायब हो सकता है। बस एक चर के लिए असाइन किया जा रहा है 'इस्तेमाल' के रूप में नहीं गिना जाता है: उस चर को उसी विधि में नीचे उल्लिखित किया जाना चाहिए ताकि ऑब्जेक्ट को जीवित रखा जा सके। –

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