आईडीसोफरेबल इंटरफ़ेस का उचित उपयोग


1657

मुझे Microsoft दस्तावेज़ पढ़ने से पता है कि IDisposableइंटरफ़ेस का "प्राथमिक" उपयोग अप्रबंधित संसाधनों को साफ करने के लिए है।

मेरे लिए, "अनवांटेड" का अर्थ है डेटाबेस कनेक्शन, सॉकेट, विंडो हैंडल आदि जैसी चीजें। लेकिन, मैंने कोड देखा है जहां Dispose()विधि प्रबंधित संसाधनों को मुक्त करने के लिए लागू की गई है , जो मुझे बेमानी लगती है, क्योंकि कचरा कलेक्टर को ध्यान रखना चाहिए वह आप के लिए है।

उदाहरण के लिए:

public class MyCollection : IDisposable
{
    private List<String> _theList = new List<String>();
    private Dictionary<String, Point> _theDict = new Dictionary<String, Point>();

    // Die, clear it up! (free unmanaged resources)
    public void Dispose()
    {
        _theList.clear();
        _theDict.clear();
        _theList = null;
        _theDict = null;
    }

मेरा सवाल यह है कि क्या यह कचरे के संग्रहकर्ता को MyCollectionकिसी भी तेजी से इस्तेमाल की जाने वाली मेमोरी को सामान्य रूप से बना देगा?

संपादित करें : अब तक लोगों ने डेटाबेस कनेक्शन और बिटमैप जैसे अप्रबंधित संसाधनों को साफ करने के लिए IDis प्रयोज्य के उपयोग के कुछ अच्छे उदाहरण पोस्ट किए हैं। लेकिन मान लीजिए कि _theListउपरोक्त कोड में एक लाख तार शामिल थे, और आप उस मेमोरी को अब मुक्त करना चाहते थे , बजाय कचरा कलेक्टर के इंतजार के। क्या उपरोक्त कोड पूरा करेगा?


34
मुझे स्वीकार किया गया उत्तर पसंद है क्योंकि यह आपको आईडीसिसोपयोगी उपयोग करने का सही 'पैटर्न' बताता है, लेकिन जैसे ओपी ने अपने संपादन में कहा, यह उसके इच्छित प्रश्न का उत्तर नहीं देता है। जीडीएस को जीडीपीसियस 'कॉल' नहीं करता है, यह सिर्फ एक वस्तु को नष्ट करने के रूप में चिह्नित करता है। लेकिन जीसी को किक करने के लिए इंतजार करने के बजाय स्मृति को 'अभी' मुक्त करने का वास्तविक तरीका क्या है? मुझे लगता है कि यह सवाल अधिक चर्चा का पात्र है।
पुनीत वोरा

40
IDisposableकुछ भी चिह्नित नहीं करता है। Disposeविधि करता है यह उदाहरण द्वारा इस्तेमाल किया संसाधनों को साफ करने के करना है क्या। इसका जीसी से कोई लेना-देना नहीं है।
जॉन सॉन्डर्स

4
@ जॉन। मैं समझता हूं IDisposable। और यही कारण है कि मैंने कहा कि स्वीकृत उत्तर ओपी के इच्छित प्रश्न (और फॉलो-अप एडिट) का जवाब नहीं देता है कि क्या आईडीआईओएस के लिए <i> मेमोरी को खाली करने में मदद मिलेगी </ i>। चूँकि IDisposableफ्रीजिंग मेमोरी से कोई लेना-देना नहीं है, केवल संसाधन हैं, तो जैसा कि आपने कहा, प्रबंधित संदर्भों को शून्य करने के लिए बिल्कुल भी सेट करने की आवश्यकता नहीं है, जो ओपी अपने उदाहरण में कर रहा था। तो, उनके प्रश्न का सही उत्तर है "नहीं, यह किसी भी तेजी से मुक्त स्मृति में मदद नहीं करता है। वास्तव में, यह मुफ्त स्मृति को केवल संसाधनों में मदद नहीं करता है"। लेकिन वैसे भी, आपके इनपुट के लिए धन्यवाद।
पुनीत वोरा

9
@desigeek: यदि यह मामला है, तो आपको "जीडी को 'कॉल नहीं करना चाहिए" आईडीआईएसओपीडी को जीसी को' कॉल 'नहीं करना चाहिए, यह' ऑब्जेक्ट 'को विनाशकारी के रूप में चिह्नित करता है "
जॉन सैन्डर्स

5
@desigeek: मेमोरी को निश्चित रूप से मुक्त करने का कोई गारंटी तरीका नहीं है। आप GC.Collect () कह सकते हैं, लेकिन यह एक विनम्र अनुरोध है, मांग नहीं। आगे बढ़ने के लिए कचरा संग्रहण के लिए सभी चल रहे थ्रेड्स को निलंबित कर दिया जाना चाहिए - यदि आप अधिक सीखना चाहते हैं, तो .NET सफ़ेप पॉइंट्स की अवधारणा पर पढ़ें, जैसे कि msdn.microsoft.com/en-us/library/678ysw69(v=vs.10)। aspx । यदि किसी थ्रेड को निलंबित नहीं किया जा सकता है, जैसे कि मानवरहित कोड में कॉल होने के कारण, GC.Collect () कुछ भी नहीं कर सकता है।
कंक्रीट गनेट

जवाबों:


2608

डिस्पोजल का बिंदु मानव रहित संसाधनों को मुक्त करना है। इसे किसी बिंदु पर करने की आवश्यकता है, अन्यथा वे कभी भी साफ नहीं किए जाएंगे। कचरा संग्रहकर्ता को पता नहीं है कि किसDeleteHandle() प्रकार के चर पर कॉल करना है IntPtr, यह नहीं जानता कि उसे कॉल करने की आवश्यकता है या नहीं DeleteHandle()

नोट : एक अप्रबंधित संसाधन क्या है ? यदि आपने इसे Microsoft .NET फ्रेमवर्क में पाया है: यह प्रबंधित है। यदि आप अपने आप MSDN के आसपास poking गए, तो यह अप्रबंधित है। .NET फ्रेमवर्क में आपके लिए उपलब्ध हर चीज़ की अच्छी कम्फर्टेबल दुनिया से बाहर निकलने के लिए आपने P / Invoke कॉल्स का उपयोग किया है।

आपके द्वारा बनाई गई वस्तु को कुछ विधि को उजागर करने की आवश्यकता है , जिसे बाहरी दुनिया कॉल कर सकती है, ताकि मानव रहित संसाधनों को साफ किया जा सके। विधि को जो भी आप पसंद करते हैं उसका नाम दिया जा सकता है:

public void Cleanup()

या

public void Shutdown()

लेकिन इसके बजाय इस विधि के लिए एक मानकीकृत नाम है:

public void Dispose()

यहां तक ​​कि एक इंटरफ़ेस भी बनाया गया था IDisposable, जिसमें बस एक तरीका है:

public interface IDisposable
{
   void Dispose()
}

इसलिए आप अपनी वस्तु को IDisposableइंटरफ़ेस से बाहर कर देते हैं, और इस तरह से आप वादा करते हैं कि आपने अपने अप्रबंधित संसाधनों को साफ करने के लिए उस एकल विधि को लिखा है:

public void Dispose()
{
   Win32.DestroyHandle(this.CursorFileBitmapIconServiceHandle);
}

और आपने कल लिया। सिवाय आप बेहतर कर सकते हैं।


क्या होगा यदि आपकी वस्तु ने 250MB System.Drawing.Bitmap (यानी .NET प्रबंधित बिटमैप वर्ग) को किसी प्रकार के फ्रेम बफर के रूप में आवंटित किया है ? ज़रूर, यह एक प्रबंधित .NET ऑब्जेक्ट है, और कचरा संग्रहकर्ता इसे मुक्त करेगा। लेकिन क्या आप वास्तव में 250 एमबी मेमोरी छोड़ना चाहते हैं, बस वहां बैठे - कचरा इकट्ठा करने वाले के लिए आखिरकार साथ आना और उसे मुक्त करना है? क्या होगा अगर एक खुला डेटाबेस कनेक्शन है ? निश्चित रूप से हम नहीं चाहते हैं कि कनेक्शन खुला रहे, वस्तु को अंतिम रूप देने के लिए जीसी का इंतजार करना चाहिए।

यदि उपयोगकर्ता ने कॉल किया है Dispose()(मतलब वे अब ऑब्जेक्ट का उपयोग करने की योजना नहीं बनाते हैं) तो उन बेकार बिटमैप और डेटाबेस कनेक्शन से छुटकारा क्यों नहीं मिलता है?

तो अब हम करेंगे:

  • अप्रबंधित संसाधनों से छुटकारा पाएं (क्योंकि हमें), और
  • प्रबंधित संसाधनों से छुटकारा पाएं (क्योंकि हम सहायक बनना चाहते हैं)

तो आइए Dispose()उन प्रबंधित वस्तुओं से छुटकारा पाने के लिए हमारी विधि को अपडेट करें:

public void Dispose()
{
   //Free unmanaged resources
   Win32.DestroyHandle(this.CursorFileBitmapIconServiceHandle);

   //Free managed resources too
   if (this.databaseConnection != null)
   {
      this.databaseConnection.Dispose();
      this.databaseConnection = null;
   }
   if (this.frameBufferImage != null)
   {
      this.frameBufferImage.Dispose();
      this.frameBufferImage = null;
   }
}

और सब अच्छा है, इसके अलावा आप बेहतर कर सकते हैं !


क्या होगा यदि व्यक्ति आपकी वस्तु पर कॉल करना भूल गयाDispose() ? तब वे कुछ अप्रबंधित संसाधनों को लीक कर देते थे !

नोट: वे प्रबंधित संसाधनों को लीक नहीं करेंगे , क्योंकि अंततः कचरा कलेक्टर एक पृष्ठभूमि थ्रेड पर, और किसी भी अप्रयुक्त ऑब्जेक्ट से जुड़ी मेमोरी को चलाने के लिए जा रहा है। यह आपके वस्तु, और किसी भी प्रबंधित वस्तुओं आप का उपयोग (जैसे शामिल होंगे Bitmapऔर DbConnection)।

यदि व्यक्ति कॉल करना भूल गया Dispose(), तो हम अभी भी अपने बेकन को बचा सकते हैं ! हमारे पास अभी भी उनके लिए इसे कॉल करने का एक तरीका है : जब कचरा कलेक्टर आखिरकार हमारी वस्तु को मुक्त करने (यानी अंतिम रूप देने) के लिए चारों ओर हो जाता है।

नोट: कचरा कलेक्टर अंततः सभी प्रबंधित वस्तुओं को मुक्त कर देगा। जब यह होता है, तो यह Finalize ऑब्जेक्ट पर विधि को कॉल करता है । जीसी आपके डिस्पोजल विधि के बारे में नहीं जानता, या देखभाल नहीं करता है । यह सिर्फ एक नाम था जिसे हमने एक विधि के लिए चुना था जिसे हम कॉल करते हैं जब हम अप्रबंधित सामान से छुटकारा चाहते हैं।

गारबेज कलेक्टर द्वारा हमारी वस्तु का विनाश उन pesky मानव रहित संसाधनों को मुक्त करने का सही समय है। हम इस Finalize()विधि को ओवरराइड करके करते हैं।

नोट: C # में, आप स्पष्ट रूप से Finalize()विधि को ओवरराइड नहीं करते हैं । आप एक ऐसी विधि लिखते हैं जो C ++ विध्वंसक की तरह दिखती है , और संकलक उस Finalize()तरीके को अपनाता है:

~MyObject()
{
    //we're being finalized (i.e. destroyed), call Dispose in case the user forgot to
    Dispose(); //<--Warning: subtle bug! Keep reading!
}

लेकिन उस कोड में एक बग है। आप देखते हैं, कचरा कलेक्टर एक पृष्ठभूमि धागे पर चलता है ; आप उस क्रम को नहीं जानते हैं जिसमें दो वस्तुएं नष्ट हो जाती हैं। यह पूरी तरह से संभव है कि आपके Dispose()कोड में, जिस प्रबंधित वस्तु से आप छुटकारा पाने की कोशिश कर रहे हैं (क्योंकि आप मददगार बनना चाहते थे) अब नहीं है:

public void Dispose()
{
   //Free unmanaged resources
   Win32.DestroyHandle(this.gdiCursorBitmapStreamFileHandle);

   //Free managed resources too
   if (this.databaseConnection != null)
   {
      this.databaseConnection.Dispose(); //<-- crash, GC already destroyed it
      this.databaseConnection = null;
   }
   if (this.frameBufferImage != null)
   {
      this.frameBufferImage.Dispose(); //<-- crash, GC already destroyed it
      this.frameBufferImage = null;
   }
}

तो आपको जो कुछ भी चाहिए वह यह Finalize()बताने का एक तरीका है Dispose()कि इसे किसी भी प्रबंधित संसाधनों को नहीं छूना चाहिए (क्योंकि वे अब वहां नहीं हो सकते हैं), जबकि अभी भी मानव रहित संसाधनों को मुक्त करना है।

ऐसा करने के लिए मानक पैटर्न है Finalize()और Dispose()दोनों एक तिहाई (!) विधि कहते हैं; यदि आप यह कहते हुए बुलियन पास करते हैं कि आप इसे Dispose()(विरोध के अनुसार Finalize()) कह रहे हैं , तो इसका मतलब है कि प्रबंधित संसाधनों को मुक्त करना सुरक्षित है।

इस आंतरिक विधि को "CoreDispose", या "MyInternalDispose" जैसे कुछ मनमाने नाम दिए जा सकते हैं, लेकिन इसे कॉल करने की परंपरा है Dispose(Boolean):

protected void Dispose(Boolean disposing)

लेकिन एक अधिक उपयोगी पैरामीटर नाम हो सकता है:

protected void Dispose(Boolean itIsSafeToAlsoFreeManagedObjects)
{
   //Free unmanaged resources
   Win32.DestroyHandle(this.CursorFileBitmapIconServiceHandle);

   //Free managed resources too, but only if I'm being called from Dispose
   //(If I'm being called from Finalize then the objects might not exist
   //anymore
   if (itIsSafeToAlsoFreeManagedObjects)  
   {    
      if (this.databaseConnection != null)
      {
         this.databaseConnection.Dispose();
         this.databaseConnection = null;
      }
      if (this.frameBufferImage != null)
      {
         this.frameBufferImage.Dispose();
         this.frameBufferImage = null;
      }
   }
}

और आप अपनी IDisposable.Dispose()विधि के कार्यान्वयन को इसमें बदल देते हैं:

public void Dispose()
{
   Dispose(true); //I am calling you from Dispose, it's safe
}

और आपका अंतिम रूप:

~MyObject()
{
   Dispose(false); //I am *not* calling you from Dispose, it's *not* safe
}

नोट : यदि आपकी वस्तु किसी ऐसी वस्तु से उतरती है Dispose, जो लागू होती है , तो जब आप ओवरराइड करें तो उनकी बेस डिस्पोज विधि को कॉल करना न भूलें :

public override void Dispose()
{
    try
    {
        Dispose(true); //true: safe to free managed resources
    }
    finally
    {
        base.Dispose();
    }
}

और सब अच्छा है, इसके अलावा आप बेहतर कर सकते हैं !


यदि उपयोगकर्ता Dispose()आपकी वस्तु पर कॉल करता है, तो सब कुछ साफ हो गया है। बाद में, जब कचरा कलेक्टर के साथ आता है और अंतिम रूप से कॉल करता है, तो यह फिर से कॉल करेगा Dispose

न केवल यह बेकार है, लेकिन अगर आपकी वस्तु में पिछली कॉल से पहले से निपटाई गई वस्तुओं के संदर्भ हैं Dispose(), तो आप उन्हें फिर से निपटाने की कोशिश करेंगे!

आप अपने कोड में देखेंगे कि मैं उन वस्तुओं के संदर्भों को हटाने के लिए सावधान था, जिन्हें मैंने निपटाया है, इसलिए मैं Disposeएक जंक ऑब्जेक्ट संदर्भ पर कॉल करने का प्रयास नहीं करता । लेकिन उस में रेंगने से एक सूक्ष्म बग को नहीं रोका।

जब उपयोगकर्ता कॉल करता है Dispose(): हैंडल CursorFileBitmapIconServiceHandle नष्ट हो जाता है। बाद में जब कचरा कलेक्टर चलता है, तो वह उसी हैंडल को फिर से नष्ट करने की कोशिश करेगा।

protected void Dispose(Boolean iAmBeingCalledFromDisposeAndNotFinalize)
{
   //Free unmanaged resources
   Win32.DestroyHandle(this.CursorFileBitmapIconServiceHandle); //<--double destroy 
   ...
}

जिस तरह से आप इसे ठीक करते हैं वह कचरा कलेक्टर को बताता है कि उसे ऑब्जेक्ट को अंतिम रूप देने में परेशान होने की आवश्यकता नहीं है - इसके संसाधनों को पहले ही साफ कर दिया गया है, और अधिक काम की आवश्यकता नहीं है। आप विधि GC.SuppressFinalize()में कॉल करके ऐसा करते हैं Dispose():

public void Dispose()
{
   Dispose(true); //I am calling you from Dispose, it's safe
   GC.SuppressFinalize(this); //Hey, GC: don't bother calling finalize later
}

अब जब कि उपयोगकर्ता ने कॉल किया है Dispose(), हमारे पास है:

  • मानव रहित संसाधनों को मुक्त किया
  • संसाधनों का प्रबंधन किया

जीसी में अंतिम बिंदु चलाने वाले का कोई मतलब नहीं है - सब कुछ का ध्यान रखा गया है।

क्या मैं अप्रबंधित संसाधनों की सफाई के लिए अंतिम रूप का उपयोग नहीं कर सकता हूं?

के लिए प्रलेखन Object.Finalizeकहता है:

अंतिम विधि का उपयोग वस्तु को नष्ट करने से पहले वर्तमान वस्तु द्वारा आयोजित मानव रहित संसाधनों पर सफाई संचालन करने के लिए किया जाता है।

लेकिन MSDN प्रलेखन यह भी कहता है IDisposable.Dispose:

अप्रबंधित संसाधनों को मुक्त करने, जारी करने या रीसेट करने से जुड़े एप्लिकेशन-परिभाषित कार्य करता है।

तो यह कौन सा है? मानव रहित संसाधनों की सफाई के लिए मेरे लिए कौन सा स्थान है? उत्तर है:

यह तुम्हारी पसंद है! लेकिन चुनें Dispose

आप निश्चित रूप से अपने अप्रबंधित सफाई को अंतिम रूप दे सकते हैं:

~MyObject()
{
   //Free unmanaged resources
   Win32.DestroyHandle(this.CursorFileBitmapIconServiceHandle);

   //A C# destructor automatically calls the destructor of its base class.
}

उस समस्या से आपको कोई मतलब नहीं है जब कचरा इकट्ठा करने वाला आपकी वस्तु को अंतिम रूप देने में जुट जाएगा। आपके संयुक्त राष्ट्र के प्रबंधित, गैर-आवश्यक, संयुक्त राष्ट्र के उपयोग किए गए मूल संसाधन तब तक चिपकेंगे जब तक कि कचरा कलेक्टर अंततः नहीं चलता। तब यह आपकी अंतिम विधि कहेगा; मानव रहित संसाधनों की सफाई। Object.Finalize के प्रलेखन यह बताते हैं:

अंतिम समय जब अंजाम होता है अपरिभाषित। अपनी कक्षा के उदाहरणों के लिए संसाधनों के निर्धारक रिलीज को सुनिश्चित करने के लिए, एक करीबी तरीका लागू करें या एक IDisposable.Disposeकार्यान्वयन प्रदान करें

यह Disposeमानव रहित संसाधनों को साफ करने के लिए उपयोग करने का गुण है ; आपको पता है, और नियंत्रण, जब अप्रबंधित संसाधन साफ ​​कर रहे हैं। उनका विनाश "नियतात्मक" है


अपने मूल प्रश्न का उत्तर देने के लिए: जीसी को करने का निर्णय लेने के बजाय, अब मेमोरी को क्यों न जारी करें? मेरे पास एक फेशियल रिकॉग्निशन सॉफ्टवेयर है जो 530 एमबी आंतरिक छवियों से छुटकारा पाने की आवश्यकता है , क्योंकि अब उनकी कोई आवश्यकता नहीं है। जब हम नहीं करते हैं: मशीन एक स्वैपिंग पड़ाव के लिए पीसती है।

बोनस पढ़ना

जो कोई भी इस सवाल का जवाब की शैली (समझा पसंद करती है के लिए क्यों है, तो कैसे स्पष्ट हो जाता है), मैं सुझाव है कि आप डॉन बॉक्स की असेंशियल कॉम के अध्याय एक पढ़ें:

35 पृष्ठों में वह द्विआधारी वस्तुओं का उपयोग करने की समस्याओं की व्याख्या करता है, और आपकी आंखों के सामने COM को लागू करता है। एक बार जब आप का एहसास क्यों कॉम की, शेष 300 पृष्ठों स्पष्ट हैं, और सिर्फ विस्तार माइक्रोसॉफ्ट के कार्यान्वयन।

मुझे लगता है कि हर प्रोग्रामर जो कभी वस्तुओं या कॉम के साथ निपटा है, बहुत कम से कम, पहले अध्याय को पढ़ना चाहिए। यह किसी भी चीज़ का सबसे अच्छा विवरण है।

अतिरिक्त बोनस पढ़ना

जब आप जो कुछ भी जानते हैं वह एरिक लिपर्ट द्वारा गलत है

इसलिए वास्तव में एक सही फाइनल लिखना बहुत मुश्किल है, और जो सबसे अच्छी सलाह मैं आपको दे सकता हूं वह है कोशिश न करना


12
आप बेहतर कर सकते हैं - आपको निपटान में GC.SuppressFinalize () में कॉल जोड़ने की आवश्यकता है।
कुर्सी

55
@ डैनियल इयरविकर: यह सच है। Microsoft आपके लिए Win32 का उपयोग पूरी तरह से रोकना पसंद करेगा, और अच्छी तरह से अमूर्त, पोर्टेबल, डिवाइस स्वतंत्र .NET फ्रेमवर्क कॉल्स से चिपकेगा। यदि आप नीचे ऑपरेटिंग सिस्टम के आसपास poking जाना चाहते हैं; क्योंकि आपको लगता है कि आप जानते हैं कि ओएस क्या चल रहा है: आप अपने जीवन को अपने हाथों में ले रहे हैं। प्रत्येक .NET ऐप विंडोज, या डेस्कटॉप पर नहीं चल रहा है।
इयान बॉयड

34
यह एक शानदार उत्तर है, लेकिन मुझे लगता है कि यह एक मानक मामले के लिए अंतिम कोड सूची से लाभान्वित होगा और एक ऐसे मामले के लिए जहां वर्ग एक आधारभूत से प्राप्त होता है जो पहले से ही लागू होता है। जैसे यहाँ पढ़ा जा रहा है ( msdn.microsoft.com/en-us/library/aa720161%28v=vs.71%29.aspx ) और साथ ही मैं उलझन में पड़ गया हूं कि क्लास से पहले आने पर मुझे क्या करना चाहिए जो पहले से ही डिसप्लिमेंट है ( हे मैं इस के लिए नया हूँ)।
पूर्णांक inte५३

5
@GregS, और अन्य: आम तौर पर मैं संदर्भों को सेट करने में परेशान नहीं होता null। सबसे पहले, इसका मतलब है कि आप उन्हें नहीं बना सकते हैं readonly, और दूसरी बात, आपको बहुत ही बदसूरत !=nullचेक करना होगा (उदाहरण के कोड में)। आपके पास एक ध्वज हो सकता है disposed, लेकिन इसके बारे में परेशान नहीं करना आसान है। .NET जीसी पर्याप्त आक्रामक है कि किसी क्षेत्र के संदर्भ को उस xसमय तक 'उपयोग' में नहीं गिना जाएगा जब तक कि यह x.Dispose()रेखा से गुजरता नहीं है ।
बजे porges

7
डॉन बॉक्स की पुस्तक के दूसरे पृष्ठ में आपने उल्लेख किया है, वह खोज एल्गोरिथ्म के ओ (1) कार्यान्वयन के उदाहरण का उपयोग करता है, जिसका "विवरण पाठक के लिए एक अभ्यास के रूप में छोड़ दिया जाता है"। मैं हँसा।
WIP

65

IDisposableअक्सर usingबयान का फायदा उठाने और प्रबंधित वस्तुओं की निर्धारक सफाई के लिए एक आसान तरीके का लाभ उठाने के लिए उपयोग किया जाता है ।

public class LoggingContext : IDisposable {
    public Finicky(string name) {
        Log.Write("Entering Log Context {0}", name);
        Log.Indent();
    }
    public void Dispose() {
        Log.Outdent();
    }

    public static void Main() {
        Log.Write("Some initial stuff.");
        try {
            using(new LoggingContext()) {
                Log.Write("Some stuff inside the context.");
                throw new Exception();
            }
        } catch {
            Log.Write("Man, that was a heavy exception caught from inside a child logging context!");
        } finally {
            Log.Write("Some final stuff.");
        }
    }
}

6
मुझे वह पसंद है, व्यक्तिगत रूप से, लेकिन यह वास्तव में रूपरेखा डिजाइन दिशानिर्देशों के साथ नहीं है।
mqp

4
मैं इसे उचित डिजाइन पर विचार करूंगा क्योंकि यह आसान नियतात्मक scopes और गुंजाइश निर्माण / क्लिनअप को सक्षम करता है, खासकर जब अपवाद-हैंडलिंग, लॉकिंग और जटिल तरीकों से अनवांटेड-रिसोर्स-ब्लॉक का उपयोग करके रुक-रुक कर होता है। भाषा इसे प्रथम श्रेणी की सुविधा प्रदान करती है।
18

यह FDG में निर्दिष्ट नियमों का बिल्कुल पालन नहीं करता है, लेकिन यह निश्चित रूप से पैटर्न का एक वैध उपयोग है क्योंकि इसे "स्टेटमेंट का उपयोग करके" उपयोग करने के लिए आवश्यक है।
स्कॉट डॉरमैन

2
जब तक Log.Outdent फेंक नहीं देता, तब तक निश्चित रूप से इसमें कुछ भी गलत नहीं है।
डैनियल इयरविकर

1
करने के लिए विभिन्न जवाब है, यह अपवाद सुरक्षा के लिए "दायरे वाला व्यवहार" प्राप्त करने के लिए एक साधन के रूप IDisposable और "का उपयोग" का उपयोग करने अपमानजनक? इस तकनीक को विभिन्न लोग क्यों पसंद / नापसंद करते हैं, इस पर थोड़ा और विस्तार में जाएं। यह कुछ हद तक विवादास्पद है।
ब्रायन

44

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

डिस्पोज़ पैटर्न को लागू करने के तरीके के बारे में अधिक जानकारी के लिए आप इस लेख पर एक नज़र डाल सकते हैं , लेकिन यह मूल रूप से इस तरह दिखता है:

public class SimpleCleanup : IDisposable
{
    // some fields that require cleanup
    private SafeHandle handle;
    private bool disposed = false; // to detect redundant calls

    public SimpleCleanup()
    {
        this.handle = /*...*/;
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                // Dispose managed resources.
                if (handle != null)
                {
                    handle.Dispose();
                }
            }

            // Dispose unmanaged managed resources.

            disposed = true;
        }
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

विधि जो यहां सबसे महत्वपूर्ण है वह है डिस्पोज (बूल), जो वास्तव में दो अलग-अलग परिस्थितियों में चलती है:

  • disposing == true: विधि को उपयोगकर्ता के कोड द्वारा प्रत्यक्ष या अप्रत्यक्ष रूप से कहा जाता है। प्रबंधित और अप्रबंधित संसाधनों का निपटान किया जा सकता है।
  • disposing == false: विधि को अंतिम रूप से अंदर से रनटाइम द्वारा बुलाया गया है, और आपको अन्य वस्तुओं का संदर्भ नहीं देना चाहिए। केवल मानव रहित संसाधनों को निपटाया जा सकता है।

बस GC को सफाई करने में ध्यान देने की समस्या यह है कि जब जीसी एक संग्रह चक्र चलाएगा (तो आप GC.Collect () कॉल कर सकते हैं, लेकिन आपके पास वास्तव में संसाधन नहीं रह सकते हैं) पर कोई वास्तविक नियंत्रण नहीं है। जरूरत से ज्यादा लंबा। याद रखें, कॉलिंग डिस्पोज़ () वास्तव में एक संग्रह चक्र का कारण नहीं बनता है या किसी भी तरह से जीसी को वस्तु को इकट्ठा / मुक्त करने का कारण बनता है; यह बस इस्तेमाल किए गए संसाधनों की अधिक निर्धारक सफाई का साधन प्रदान करता है और GC को बताता है कि यह सफाई पहले ही निष्पादित की जा चुकी है।

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

.NET में स्ट्रिंग के बाद से आपका परिदृश्य वास्तव में मान्य नहीं है। किसी भी असंगठित संसाधनों का उपयोग नहीं करते हैं और न ही आईडीसोप्रोजेबल को लागू करते हैं, उन्हें "साफ" करने के लिए मजबूर करने का कोई तरीका नहीं है।


4
क्या आप फाइनल को लागू करना नहीं भूले?
बुद्ध

@ बड्डा: नहीं, वह सेफहैंडल का इस्तेमाल कर रहा है। विध्वंसक की कोई जरूरत नहीं।
हेन्क होल्टरमैन

9
डिसपोज़ल () के लिए कई कॉल्स के लिए सुरक्षा नेट जोड़ने के लिए +1। युक्ति कहता है कि एकाधिक कॉल सुरक्षित होनी चाहिए। बहुत से Microsoft वर्ग इसे लागू करने में विफल होते हैं, और आपको कष्टप्रद ObjectDisposedException मिलता है।
जेसी चिशोल्म

5
लेकिन डिस्पोज़ (बूल डिस्पोज़ करना) आपके सिंपलक्लेनअप क्लास पर अपना तरीका है और इसे कभी भी फ्रेमवर्क द्वारा नहीं बुलाया जाएगा। चूंकि आप इसे केवल एक पैरामीटर के रूप में "सही" के साथ कहते हैं, इसलिए 'डिस्पोज़ करना' कभी भी गलत नहीं होगा। आपका कोड आईडीआईएसडीओपी के लिए एमएसडीएन उदाहरण के समान है, लेकिन अंतिम रूप में कमी है, जैसा कि @ बड्डा ने बताया, जो कि डिस्पोजिंग = झूठ के साथ कॉल कहां से आएगा।
योयो

19

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

प्रबंधित / अप्रबंधित और अन्य उत्तरों में चर्चा के बारे में सामान्य प्रश्न के लिए, मुझे लगता है कि इस प्रश्न के किसी भी उत्तर को अप्रबंधित संसाधन की परिभाषा के साथ शुरू करना होगा।

यह बात उबलती है कि एक फ़ंक्शन है जिसे आप सिस्टम को एक स्थिति में डालने के लिए कॉल कर सकते हैं, और एक अन्य फ़ंक्शन है जिसे आप उस स्थिति से वापस लाने के लिए कॉल कर सकते हैं। अब, विशिष्ट उदाहरण में, पहला एक फ़ंक्शन हो सकता है जो एक फ़ाइल हैंडल लौटाता है, और दूसरा एक कॉल हो सकता है CloseHandle

लेकिन - और यह कुंजी है - वे कार्यों के किसी भी मिलान जोड़ी हो सकते हैं। एक राज्य का निर्माण करता है, दूसरा उसे फाड़ देता है। यदि राज्य बनाया गया है, लेकिन अभी तक नहीं फटा है, तो संसाधन का एक उदाहरण मौजूद है। आपको सही समय पर होने वाली अशांति के लिए व्यवस्था करना होगा - संसाधन सीएलआर द्वारा प्रबंधित नहीं किया जाता है। केवल स्वचालित रूप से प्रबंधित संसाधन प्रकार मेमोरी है। दो प्रकार हैं: जीसी, और स्टैक। मान प्रकार को स्टैक द्वारा प्रबंधित किया जाता है (या संदर्भ प्रकार के अंदर एक सवारी को रोककर), और संदर्भ प्रकार को जीसी द्वारा प्रबंधित किया जाता है।

इन कार्यों से राज्य परिवर्तन हो सकते हैं जो स्वतंत्र रूप से इंटरलेव किया जा सकता है, या पूरी तरह से नेस्टेड होने की आवश्यकता हो सकती है। राज्य परिवर्तन थ्रेडसफ़ हो सकते हैं, या वे नहीं हो सकते हैं।

न्याय के प्रश्न में उदाहरण देखें। लॉग फ़ाइल के इंडेंटेशन में परिवर्तन पूरी तरह से नेस्टेड होना चाहिए, या यह सब गलत हो जाता है। इसके अलावा वे थ्रेडसेफ़ होने की संभावना नहीं है।

अपने अनवांटेड संसाधनों को साफ करने के लिए कचरे के संग्रहकर्ता के साथ एक सवारी को रोकना संभव है। लेकिन केवल तभी जब राज्य परिवर्तन कार्य थ्रेडसेफ़ हैं और दो राज्यों में जीवनकाल हो सकते हैं जो किसी भी तरह से ओवरलैप होते हैं। इसलिए जस्टिस के संसाधन के उदाहरण में अंतिम रूप नहीं होना चाहिए! यह सिर्फ किसी की मदद नहीं करेगा।

उन प्रकार के संसाधनों के लिए, आप IDisposableअंतिम रूप से लागू हो सकते हैं । फ़ाइनलीज़र बिल्कुल वैकल्पिक है - यह होना चाहिए। यह कई पुस्तकों में उल्लिखित है या नहीं भी लिखा गया है।

फिर आपको usingयह सुनिश्चित करने के लिए कि Disposeयह कहा जाता है, के अवसर का उपयोग करना होगा । यह अनिवार्य रूप से स्टैक के साथ एक सवारी को रोकना है (जैसे कि अंतिम जीसी के usingलिए है, स्टैक के लिए है)।

लापता हिस्सा यह है कि आपको मैन्युअल रूप से Dispose लिखना है और इसे अपने फ़ील्ड और अपने बेस क्लास पर कॉल करना है। C ++ / CLI प्रोग्रामर को ऐसा नहीं करना है। संकलक इसे ज्यादातर मामलों में उनके लिए लिखते हैं।

एक विकल्प है, जो मैं उन राज्यों के लिए पसंद करता हूं, जो घोंसले को पूरी तरह से पसंद करते हैं और थ्रेडसेफ़ नहीं हैं (इसके अलावा और कुछ भी नहीं, आईडीसिसोप्लॉरी से परहेज करने से आपको किसी ऐसे व्यक्ति के साथ बहस करने की समस्या होती है जो हर वर्ग के लिए एक फ़ाइज़र जोड़ने का विरोध नहीं कर सकता है जो आईडीप्लॉक्सिक लागू करता है) ।

क्लास लिखने के बजाय, आप एक फंक्शन लिखते हैं। फ़ंक्शन एक प्रतिनिधि को वापस कॉल करने के लिए स्वीकार करता है:

public static void Indented(this Log log, Action action)
{
    log.Indent();
    try
    {
        action();
    }
    finally
    {
        log.Outdent();
    }
}

और फिर एक सरल उदाहरण होगा:

Log.Write("Message at the top");
Log.Indented(() =>
{
    Log.Write("And this is indented");

    Log.Indented(() =>
    {
        Log.Write("This is even more indented");
    });
});
Log.Write("Back at the outermost level again");

लैम्बडा को एक कोड ब्लॉक के रूप में कार्य किया जा रहा है, इसलिए यह ऐसा है जैसे आप उसी उद्देश्य को पूरा करने के लिए अपनी स्वयं की नियंत्रण संरचना बनाते हैं using, सिवाय इसके कि आपको कॉल करने वाले को गाली देने का कोई खतरा नहीं है। वहाँ कोई रास्ता नहीं है कि वे संसाधन को साफ करने में विफल हो सकते हैं।

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


पुन: "डिस्पोज़ को इस पर कॉल किए जाने के बाद ऑब्जेक्ट के तरीकों के लिए आगे कोई कॉल नहीं होना चाहिए"। “मुझे ऑपरेटिव शब्द होना चाहिए। यदि आपके पास अतुल्यकालिक क्रियाएं लंबित हैं, तो वे आपकी वस्तु के निपटान के बाद आ सकते हैं। एक ObjectDisposedException के कारण।
जेसी चिशोल्म

तुम्हारा केवल एक अन्य उत्तर है जो खदान के अलावा इस विचार से स्पर्श करता है कि मानव रहित संसाधन राज्य को घेर लेते हैं जो कि जीसी को समझ में नहीं आता है। हालांकि, एक अप्रबंधित संसाधन का एक प्रमुख पहलू यह है कि एक या एक से अधिक संस्थाओं को जिनके राज्य को अपने राज्य में साफ-सफाई की आवश्यकता हो सकती है, भले ही वह संसाधन मौजूद हो, जो उस संसाधन का मालिक नहीं है। आपको मेरी परिभाषा कैसी लगी? बहुत समान है, लेकिन मुझे लगता है कि यह "संसाधन" को थोड़ी अधिक संज्ञा-ईश बनाता है (यह बाहरी वस्तु द्वारा "व्यवहार" है, इसके व्यवहार को बदलने के लिए, जब इसकी सेवाओं की अब आवश्यकता नहीं है, तो अधिसूचना के बदले में)
सुपरकैट

@supercat - यदि आप रुचि रखते हैं तो मैंने उपरोक्त पोस्ट लिखने के कुछ दिनों बाद निम्नलिखित पोस्ट लिखी: smellegantcode.wordpress.com/2009/02/13/…
डैनियल

1
@DanielEarwicker: दिलचस्प लेख, हालांकि मैं कम से कम एक प्रकार के अप्रबंधित संसाधन के बारे में सोच सकता हूं जो आप वास्तव में कवर नहीं करते हैं: लंबे समय तक जीवित वस्तुओं से घटनाओं के लिए सदस्यता। ईवेंट सब्सक्रिप्शन फनी हैं, लेकिन यहां तक ​​कि अगर मेमोरी को डिस्पोज़ करने में असीमित विफलता थी, तो महंगा हो सकता है। उदाहरण के लिए, संग्रह के लिए एक एन्यूमरेटर जो एन्यूमरेशन के दौरान संशोधन की अनुमति देता है, उसे संग्रह से सूचनाएं अपडेट करने के लिए सदस्यता लेने की आवश्यकता हो सकती है, और संग्रह को अपने जीवनकाल में कई बार अपडेट किया जा सकता है। अगर
एनुमरेटर को

1
संचालन की जोड़ी enterऔर इस exitबात का मूल है कि मैं एक संसाधन के बारे में कैसे सोचता हूं। घटनाओं पर सदस्यता / सदस्यता समाप्त करना बिना किसी कठिनाई के फिट होना चाहिए। ऑर्थोगोनल / कवक विशेषताओं के संदर्भ में यह स्मृति रिसाव से व्यावहारिक रूप से अप्रभेद्य है। (यह सदस्यता के रूप में बहुत ही आश्चर्यजनक है, केवल एक सूची में वस्तुओं को जोड़ रहा है।)
डैनियल इयरविकर

17

परिदृश्य मैं आईडीसॉप्रयोगी का उपयोग करता हूं: अप्रबंधित संसाधनों को साफ करना, घटनाओं के लिए सदस्यता समाप्त करना, करीबी कनेक्शन

आइडिओसॉपी ( थ्रेडसेफ़ नहीं ) को लागू करने के लिए मुहावरे का उपयोग करता हूं :

class MyClass : IDisposable {
    // ...

    #region IDisposable Members and Helpers
    private bool disposed = false;

    public void Dispose() {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    private void Dispose(bool disposing) {
        if (!this.disposed) {
            if (disposing) {
                // cleanup code goes here
            }
            disposed = true;
        }
    }

    ~MyClass() {
        Dispose(false);
    }
    #endregion
}

पूर्ण पैटर्न स्पष्टीकरण msdn.microsoft.com/en-us/library/b1yfkh5e.aspx
लाइसेंसक्यू

3
जब तक आपके पास अप्रबंधित संसाधन न हों, तब तक किसी भी अंतिम रूप में शामिल नहीं होना चाहिए। फिर भी, पसंदीदा कार्यान्वयन सेफहैंडल में अप्रबंधित संसाधन को लपेटना है।
डेव ब्लैक

11

हां, यह कोड पूरी तरह से अनावश्यक और अनावश्यक है और यह कचरा संग्रहकर्ता को ऐसा कुछ भी नहीं करता है जो यह अन्यथा नहीं करेगा (एक बार MyCollection का एक उदाहरण दायरे से बाहर चला जाता है, यह है।) विशेष रूप से .Clear()कॉल।

अपने संपादन का उत्तर दें: क्रमबद्ध करें। अगर मैं ऐसा करता हूं:

public void WasteMemory()
{
    var instance = new MyCollection(); // this one has no Dispose() method
    instance.FillItWithAMillionStrings();
}

// 1 million strings are in memory, but marked for reclamation by the GC

यह स्मृति प्रबंधन के उद्देश्यों के लिए कार्यात्मक रूप से समान है:

public void WasteMemory()
{
    var instance = new MyCollection(); // this one has your Dispose()
    instance.FillItWithAMillionStrings();
    instance.Dispose();
}

// 1 million strings are in memory, but marked for reclamation by the GC

यदि आपको वास्तव में वास्तव में स्मृति को इस बहुत ही त्वरित रूप से मुक्त करने की आवश्यकता है, तो कॉल करें GC.Collect()। हालांकि, यहाँ ऐसा करने का कोई कारण नहीं है। इसकी आवश्यकता होने पर मेमोरी को मुक्त कर दिया जाएगा।


2
पुन: "स्मृति को मुक्त किया जाएगा जब यह आवश्यक हो।" बल्कि कहते हैं, "जब जीसी तय करता है तो इसकी आवश्यकता होती है।" जीसी का निर्णय लेने से पहले आपको सिस्टम के प्रदर्शन के मुद्दों को देख सकते हैं कि स्मृति की वास्तव में आवश्यकता है। इसे मुक्त करना अब आवश्यक नहीं हो सकता है, लेकिन उपयोगी हो सकता है।
जेसी चिशोल्म

1
कुछ कोने के मामले हैं जिनमें एक संग्रह के भीतर संदर्भों को शून्य करना, इसके लिए संदर्भित वस्तुओं के कचरा संग्रह में तेजी ला सकता है। उदाहरण के लिए, यदि एक बड़ी सरणी बनाई गई है और छोटी-नई बनाई गई वस्तुओं के संदर्भ में भरी हुई है, लेकिन इसके लिए बहुत लंबे समय की आवश्यकता नहीं है, तो सरणी को त्यागने से उन वस्तुओं को अगले स्तर 2 जीसी तक रखा जा सकता है। इसे शून्य करते समय पहले आइटम को अगले स्तर 0 या स्तर 1 GC के लिए योग्य बना सकते हैं। सुनिश्चित करने के लिए, बड़े ऑब्जेक्ट हीप पर बड़ी अल्पकालिक वस्तुओं का होना वैसे भी icky है (मैं डिजाइन को नापसंद करता हूं) लेकिन ...
सुपरकैट

1
... इस तरह के सरणियों को शून्य करने से पहले उन्हें छोड़ने से मेरा कभी-कभी जीसी प्रभाव कम हो जाता है।
सुपरकैट

11

यदि MyCollectionकिसी भी तरह कचरा एकत्र किया जा रहा है, तो आपको इसे निपटाने की आवश्यकता नहीं है। ऐसा करने से बस सीपीयू को ज़रूरत से ज़्यादा मंथन करना पड़ेगा, और कुछ पूर्व-गणना विश्लेषण को अमान्य भी कर सकता है जो कचरा कलेक्टर ने पहले ही प्रदर्शन किया है।

मैं IDisposableऐसी चीजों को करने के लिए उपयोग करता हूं जैसे कि अप्रबंधित संसाधनों के साथ धागे का सही तरीके से निपटान किया जाता है।

EDIT स्कॉट की टिप्पणी के जवाब में:

केवल जब GC प्रदर्शन मैट्रिक्स प्रभावित होते हैं, जब एक कॉल [sic] GC.Collect () किया जाता है "

वैचारिक रूप से, जीसी वस्तु संदर्भ ग्राफ का एक दृश्य रखता है, और धागे के स्टैक फ्रेम से इसके सभी संदर्भ। यह ढेर काफी बड़ा हो सकता है और स्मृति के कई पृष्ठों को फैला सकता है। एक अनुकूलन के रूप में, जीसी उन पृष्ठों के अपने विश्लेषण को कैश करता है जो अनावश्यक रूप से पृष्ठ को पुन: व्यवस्थित करने से बचने के लिए बहुत बार बदलने की संभावना नहीं रखते हैं। जीसी कर्नेल से अधिसूचना प्राप्त करता है जब किसी पृष्ठ में डेटा बदलता है, तो यह जानता है कि पृष्ठ गंदा है और इसके लिए एक रिस्कन की आवश्यकता है। यदि संग्रह Gen0 में है, तो संभावना है कि पृष्ठ की अन्य चीजें भी बदल रही हैं, लेकिन Gen1 और Gen2 में इसकी संभावना कम है। वास्तविक रूप से, ये हुक मैक ओएस एक्स में उस टीम के लिए उपलब्ध नहीं थे, जिसने उस प्लेटफ़ॉर्म पर सिल्वरलाइट प्लग-इन काम करने के लिए जीसी को मैक में पोर्ट किया था।

संसाधनों के अनावश्यक निपटान के खिलाफ एक और बिंदु: ऐसी स्थिति की कल्पना करें जहां एक प्रक्रिया अनलोडिंग हो। यह भी कल्पना करें कि प्रक्रिया कुछ समय से चल रही है। संभावना है कि उस प्रक्रिया के कई मेमोरी पेज डिस्क पर स्वैप किए गए हैं। बहुत कम से कम अब वे L1 या L2 कैश में नहीं हैं। ऐसी स्थिति में उस एप्लिकेशन का कोई मतलब नहीं है जो उन सभी डेटा और कोड पेजों को वापस स्वैप करने के लिए अनलोड कर रहा है जो स्मृति में 'रिलीज़' संसाधनों के लिए हैं जो कि ऑपरेटिंग सिस्टम द्वारा वैसे भी जारी किए जा रहे हैं जब प्रक्रिया समाप्त हो जाती है। यह प्रबंधित और यहां तक ​​कि कुछ अप्रबंधित संसाधनों पर भी लागू होता है। केवल गैर-पृष्ठभूमि थ्रेड्स को जीवित रखने वाले संसाधनों को निपटाया जाना चाहिए, अन्यथा प्रक्रिया जीवित रहेगी।

अब, सामान्य निष्पादन के दौरान, अप्रचलित संसाधन होते हैं जिन्हें सही ढंग से साफ किया जाना चाहिए (जैसा कि @fezmonkey डेटाबेस कनेक्शन, सॉकेट, विंडो हैंडल ) को अनवांटेड मेमोरी लीक से बचने के लिए इंगित करता है । ये उन चीजों के प्रकार हैं जिनका निपटान किया जाना है। यदि आप कुछ वर्ग बनाते हैं जो एक धागा का मालिक है (और मेरे स्वामी से मेरा मतलब है कि उसने इसे बनाया है और इसलिए यह सुनिश्चित करने के लिए जिम्मेदार है कि यह बंद हो जाता है, कम से कम मेरी कोडिंग शैली से), तो उस वर्ग को सबसे अधिक संभावना लागू करनी चाहिए IDisposableऔर उस दौरान थ्रेड को फाड़ना चाहिए Dispose

.NET फ्रेमवर्क IDisposableइंटरफ़ेस को सिग्नल के रूप में उपयोग करता है , यहां तक ​​कि डेवलपर्स को चेतावनी भी देता है कि इस वर्ग को निपटाया जाना चाहिए। मैं उस ढाँचे में किसी भी प्रकार के बारे में नहीं सोच सकता हूँ जो लागू हो IDisposable(स्पष्ट इंटरफ़ेस कार्यान्वयन को छोड़कर) जहां निपटान वैकल्पिक हो।


कॉलिंग डिस्पोज़ पूरी तरह से वैध, कानूनी और प्रोत्साहित है। आमतौर पर ऐसा करने के लिए आईडीसिस प्रयोज्य को लागू करने वाली वस्तुएं होती हैं। GC प्रदर्शन मैट्रिक्स प्रभावित होने पर ही कॉल GC.Collect () किया जाता है।
स्कॉट डॉरमैन

कई .net वर्गों के लिए, निपटान "कुछ हद तक" वैकल्पिक है, जिसका अर्थ है कि उदाहरणों को त्यागना "आमतौर पर" किसी भी परेशानी का कारण नहीं होगा जब तक कि कोई व्यक्ति नए उदाहरण बनाने और उन्हें छोड़ने के लिए पागल न हो। उदाहरण के लिए, नियंत्रण के लिए संकलक-जनित कोड फ़ॉन्ट बनाने के लिए लगता है जब नियंत्रण तत्काल होते हैं और उन्हें छोड़ दिया जाता है जब प्रपत्रों का निपटान किया जाता है; यदि कोई हजारों नियंत्रण बनाता है और उसका निपटान करता है, तो यह हजारों GDI हैंडल को बाँध सकता है, लेकिन ज्यादातर मामलों में नियंत्रणों को बनाया नहीं जाता है और उन्हें नष्ट कर दिया जाता है। बहरहाल, इस तरह के परित्याग से बचने की कोशिश करनी चाहिए।
सुपरकैट

1
फोंट के मामले में, मुझे संदेह है कि समस्या यह है कि Microsoft ने वास्तव में कभी नहीं परिभाषित किया कि नियंत्रण के लिए सौंपी गई "फ़ॉन्ट" ऑब्जेक्ट को निपटाने के लिए कौन सी इकाई जिम्मेदार है; कुछ मामलों में, एक नियंत्रण एक लंबे समय तक रहने वाली वस्तु के साथ एक फ़ॉन्ट साझा कर सकता है, इसलिए नियंत्रण को निष्क्रिय करना फ़ॉन्ट खराब होगा। अन्य मामलों में, एक फ़ॉन्ट एक नियंत्रण को सौंपा जाएगा और कहीं और नहीं होगा, इसलिए यदि नियंत्रण इसे निपटान नहीं करता है तो कोई भी नहीं करेगा। संयोग से, फोंट के साथ इस कठिनाई से बचा जा सकता था एक अलग गैर-डिस्पोजेबल FontTemplate वर्ग था, क्योंकि नियंत्रण उनके फ़ॉन्ट के GDI हैंडल का उपयोग नहीं करते हैं।
सुपरकैट

वैकल्पिक Dispose()कॉल के विषय पर , देखें: stackoverflow.com/questions/913228/…
RJ Cuthbertson

7

आपके द्वारा पोस्ट किए गए उदाहरण में, यह अभी भी "मेमोरी को मुक्त नहीं करता है"। सभी मेमोरी कचरा एकत्र की जाती है, लेकिन यह मेमोरी को पहले की पीढ़ी में एकत्र करने की अनुमति दे सकती है । आपको यह सुनिश्चित करने के लिए कुछ परीक्षण चलाने होंगे।


फ्रेमवर्क डिज़ाइन दिशानिर्देश दिशानिर्देश हैं, न कि नियम। वे आपको बताते हैं कि इंटरफ़ेस मुख्य रूप से क्या है, इसका उपयोग कब करना है, इसका उपयोग कैसे करना है, और इसका उपयोग कब करना है

मैंने एक बार कोड पढ़ा था जो कि आईडीसोप्लॉरी के उपयोग में विफलता पर एक साधारण रोलबैक () था। नीचे मिनीटैक्स वर्ग डिस्पोज़ () पर एक ध्वज की जांच करेगा और यदि Commitकॉल कभी नहीं हुआ, तो वह Rollbackस्वयं कॉल करेगा । इसने अप्रत्यक्षता की एक परत को जोड़ दिया जिससे कॉलिंग कोड समझने और बनाए रखने में बहुत आसान हो गया। परिणाम कुछ इस तरह दिखे:

using( MiniTx tx = new MiniTx() )
{
    // code that might not work.

    tx.Commit();
} 

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

using( LogTimer log = new LogTimer("MyCategory", "Some message") )
{
    // code to time...
}

इसलिए यहां कुछ ठोस उदाहरण दिए गए हैं जो किसी भी मानव रहित संसाधन की सफाई नहीं करते हैं, लेकिन क्लीनर कोड बनाने के लिए सफलतापूर्वक उपयोग किए जाने वाले आईडीआईसोप्लेट का उपयोग करते हैं।


उच्च आदेश कार्यों का उपयोग करके @Daniel Earwicker के उदाहरण पर एक नज़र डालें। बेंचमार्किंग, टाइमिंग, लॉगिंग इत्यादि के लिए यह अधिक सीधा लगता है।
अलुआन हद्दद


6

मैं संयुक्त राष्ट्र-प्रबंधित संसाधनों का उपयोग या मुक्त करने के बारे में सामान्य सामान नहीं दोहराऊंगा, जो सभी को कवर किया गया है। लेकिन मैं यह बताना चाहूंगा कि एक आम गलत धारणा है।
निम्नलिखित कोड दिया

पब्लिक क्लास लार्जस्टाफ
  औजार
  निजी _Large स्ट्रिंग के रूप में ()

  'कुछ अजीब कोड का मतलब है कि _Large में अब कई मिलियन लंबे तार हैं।

  सार्वजनिक उप निस्तारण () कार्यान्वयन
    _Large = कुछ भी नहीं है
  अंत उप

मुझे एहसास है कि डिस्पोजेबल कार्यान्वयन वर्तमान दिशानिर्देशों का पालन नहीं करता है, लेकिन उम्मीद है कि आप सभी को यह विचार मिलेगा।
अब, जब डिस्पोजल कहा जाता है, तो कितनी मेमोरी मुक्त हो जाती है?

उत्तर: कोई नहीं।
कॉलिंग डिस्पोज़ अनवांटेड संसाधनों को जारी कर सकता है, यह प्रबंधित मेमोरी को पुनः प्राप्त नहीं कर सकता है, केवल जीसी ही ऐसा कर सकता है। Thats यह नहीं कहना है कि ऊपर एक अच्छा विचार नहीं है, उपरोक्त पैटर्न का पालन करना अभी भी वास्तव में एक अच्छा विचार है। एक बार जब डिस्पोजल चलाया जाता है, तो जीसी री-क्लेम करने वाली मेमोरी को बंद करने से कुछ नहीं होता है, जिसका इस्तेमाल _Large द्वारा किया जा रहा था, भले ही लार्जस्टफ का उदाहरण अभी भी स्कोप में हो। _Large में तार जीन 0 में भी हो सकते हैं, लेकिन लार्जस्टफ का उदाहरण जीन 2 हो सकता है, इसलिए फिर से, मेमोरी को जल्द ही फिर से दावा किया जाएगा।
हालांकि, ऊपर दिखाए गए डिस्पोज़ विधि को कॉल करने के लिए एक अंतिम जोड़ने का कोई मतलब नहीं है। यह सिर्फ अंतिम रूप से चलाने की अनुमति देने के लिए मेमोरी को फिर से दावा करने वाला DELAY होगा।


1
अगर इसका उदाहरण LargeStuffजनरेशन 2 को बनाने के लिए काफी लंबा है, और अगर _Largeएक नई-निर्मित स्ट्रिंग का संदर्भ है, जो कि जनरेशन 0 में है, तो यदि LargeStuffबिना आवृत्ति के इसे छोड़ दिया जाता है _Large, तो स्ट्रिंग को इसके द्वारा संदर्भित किया जाता है। _Largeअगले Gen2 संग्रह तक चारों ओर रखा जाएगा। ज़ीरोइंग से _Largeअगले जेन0 संग्रह में स्ट्रिंग को समाप्त होने दिया जा सकता है। ज्यादातर मामलों में, संदर्भों को शून्य करना मददगार नहीं है, लेकिन ऐसे मामले हैं जहां यह कुछ लाभ प्रदान कर सकता है।
सुपरकैट

5

इसके अलावा नियंत्रित करने के लिए एक मार्ग के रूप में अपनी प्राथमिक उपयोग से जीवन भर के सिस्टम संसाधन (पूरी तरह से की भयानक जवाब के अंतर्गत आने वाले इयान , प्रशंसा!), IDisposable / का उपयोग कर कॉम्बो भी करने के लिए इस्तेमाल किया जा सकता गुंजाइश (महत्वपूर्ण) वैश्विक संसाधनों की स्थिति परिवर्तन : कंसोल , धागे , प्रक्रिया , किसी भी वैश्विक वस्तु एक तरह आवेदन उदाहरण

मैंने इस पैटर्न के बारे में एक लेख लिखा है: http://pragmateek.com/c-scope-your-global-state-changes-with-idisposable-and-the-use-statement/

यह बताता है कि आप एक पुन: प्रयोज्य और पठनीय तरीके से कुछ अक्सर इस्तेमाल की जाने वाली वैश्विक स्थिति की रक्षा कैसे कर सकते हैं : कंसोल रंग , वर्तमान थ्रेड संस्कृति , एक्सेल एप्लिकेशन ऑब्जेक्ट गुण ...


4

यदि कुछ भी हो, तो मुझे उम्मीद है कि इसे छोड़ते समय कोड कम कुशल होगा।

कॉलिंग क्लियर () तरीके अनावश्यक हैं, और GC शायद ऐसा नहीं करेगा यदि डिस्पोजल ने ऐसा नहीं किया ...


2

ऐसी चीजें हैं जो Dispose()ऑपरेशन उदाहरण कोड में करता है जो एक प्रभाव हो सकता है जो MyCollectionऑब्जेक्ट के सामान्य जीसी के कारण नहीं होगा ।

यदि वस्तुओं को संदर्भित _theListया _theDictअन्य वस्तुओं द्वारा संदर्भित किया जाता है, तो वह वस्तु List<>या Dictionary<>वस्तु संग्रह के अधीन नहीं होगी, लेकिन अचानक कोई सामग्री नहीं होगी। यदि उदाहरण के अनुसार कोई डिस्पोज़ () ऑपरेशन नहीं होता, तो उन संग्रहों में उनकी सामग्री होती।

बेशक, अगर यह स्थिति थी, तो मैं इसे एक टूटी हुई डिजाइन कहूंगा - मैं सिर्फ इशारा कर रहा हूं (पैदल, मुझे लगता है) कि Dispose()ऑपरेशन पूरी तरह से निरर्थक नहीं हो सकता है, इस पर निर्भर करता है कि क्या इसके अन्य उपयोग हैं List<>या Dictionary<>नहीं हैं टुकड़े में दिखाया गया है।


वे निजी क्षेत्र हैं, इसलिए मुझे लगता है कि यह मानना ​​उचित है कि ओपी उन्हें संदर्भ नहीं दे रहा है।
mqp

1) कोड का टुकड़ा केवल उदाहरण कोड है, इसलिए मैं केवल यह इंगित कर रहा हूं कि एक साइड-इफेक्ट हो सकता है जो अनदेखी करना आसान है; 2) निजी क्षेत्र अक्सर एक गेटवे संपत्ति / विधि का लक्ष्य होते हैं - शायद बहुत अधिक (कुछ लोगों द्वारा एक व्यक्ति को पैटर्न विरोधी माना जाता है)।
माइकल बूर

2

"अप्रबंधित संसाधनों" की अधिकांश चर्चाओं के साथ एक समस्या यह है कि वे वास्तव में इस शब्द को परिभाषित नहीं करते हैं, लेकिन इसका अर्थ यह है कि इसका अप्रबंधित कोड के साथ कुछ करना है। हालांकि यह सच है कि कई प्रकार के अप्रबंधित संसाधन अनवांटेड कोड के साथ इंटरफेस करते हैं, लेकिन ऐसे शब्दों में अप्रबंधित संसाधनों के बारे में सोचना मददगार नहीं है।

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

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


खैर, IMO, अप्रबंधित वस्तु की परिभाषा स्पष्ट है; कोई भी गैर-जीसी वस्तु
इऑनिल

1
@ ईनोइल: अनवांटेड ऑब्जेक्ट! = अनवांटेड रिसोर्स। घटनाओं जैसी चीजों को पूरी तरह से प्रबंधित वस्तुओं का उपयोग करके लागू किया जा सकता है, लेकिन फिर भी अप्रबंधित संसाधनों का गठन किया जा सकता है, क्योंकि - कम से कम अल्पकालिक वस्तुओं के मामले में जो लंबे समय तक रहने वाली वस्तुओं की घटनाओं की सदस्यता लेते हैं - जीसी उन्हें साफ करने के तरीके के बारे में कुछ भी नहीं जानता है। ।
सुपरकैट


2

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

  1. यदि मेरे द्वारा बनाई गई कक्षा कुछ अप्रबंधित संसाधनों का उपयोग करती है तो इसका मतलब है कि मुझे मेमोरी को साफ करने के लिए आईडीसोफरेबल इंटरफेस भी लागू करना चाहिए।
  2. जैसे ही मैंने इसका उपयोग समाप्त किया, वस्तुओं को साफ करें।
  3. अपनी डिस्पोज़ विधि में मैं कक्षा के सभी आईडीआईसोपोटरी सदस्यों पर कॉल करता हूं और डिस्पोज करता हूं।
  4. कचरा निपटान कलेक्टर को सूचित करने के लिए मेरी डिस्पोज़ विधि में GC.SuppressFinalize (यह) कॉल करें कि मेरी वस्तु पहले ही साफ हो गई थी। मैं इसे करता हूं क्योंकि जीसी को कॉल करना महंगा ऑपरेशन है।
  5. अतिरिक्त सावधानी के रूप में मैं कई बार डिस्पोज़ () के संभावित कॉल करने का प्रयास करता हूं।
  6. कुछ समय के बाद मैं निजी सदस्य को जोड़ देता हूं। जांच और विधि कॉल में जांच की गई कि ऑब्जेक्ट साफ हो गया है। और अगर इसे साफ किया गया था, तो ObjectDisposedException उत्पन्न करें
    टेम्पलेट का अनुसरण करता है जो मैंने कोड में नमूने के रूप में शब्दों में वर्णित किया है:

public class SomeClass : IDisposable
    {
        /// <summary>
        /// As usually I don't care was object disposed or not
        /// </summary>
        public void SomeMethod()
        {
            if (_disposed)
                throw new ObjectDisposedException("SomeClass instance been disposed");
        }

        public void Dispose()
        {
            Dispose(true);
        }

        private bool _disposed;

        protected virtual void Dispose(bool disposing)
        {
            if (_disposed)
                return;
            if (disposing)//we are in the first call
            {
            }
            _disposed = true;
        }
    }

1
"मेरे लिए अप्रबंधित संसाधन का अर्थ है कुछ वर्ग, जो आईडीआईएसोलॉजिकल इंटरफ़ेस को लागू करते हैं या डीएलएल को कॉल के उपयोग के साथ बनाए गए कुछ।" तो आप कह रहे हैं कि किसी भी प्रकार का जो is IDisposableस्वयं को एक अप्रबंधित संसाधन माना जाना चाहिए? यह सही नहीं लगता है। इसके अलावा यदि निहितार्थ प्रकार एक शुद्ध मूल्य प्रकार है, तो आप सुझाव देते हैं कि इसे निपटाए जाने की आवश्यकता नहीं है। वह भी गलत लगता है।
एलुआन हद्दद

हर कोई खुद से न्याय करता है। मैं इसके अलावा कुछ के लिए मेरा कोड जोड़ने के लिए पसंद नहीं है। इसका मतलब है कि अगर मैं आईडीसोपायरी जोड़ता हूं, तो इसका मतलब है कि मैंने कुछ प्रकार की कार्यक्षमता बनाई है जो जीसी प्रबंधन नहीं कर सकता है या मुझे लगता है कि यह जीवनकाल ठीक से प्रबंधित नहीं कर पाएगा।
युरी ज़ाल्तेस्की

2

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

निम्नलिखित उदाहरण कुछ कोड और टिप्पणियों के साथ आईडीसोपोलेटरी पैटर्न के लिए एक अच्छा उदाहरण दिखाता है।

public class DisposeExample
{
    // A base class that implements IDisposable. 
    // By implementing IDisposable, you are announcing that 
    // instances of this type allocate scarce resources. 
    public class MyResource: IDisposable
    {
        // Pointer to an external unmanaged resource. 
        private IntPtr handle;
        // Other managed resource this class uses. 
        private Component component = new Component();
        // Track whether Dispose has been called. 
        private bool disposed = false;

        // The class constructor. 
        public MyResource(IntPtr handle)
        {
            this.handle = handle;
        }

        // Implement IDisposable. 
        // Do not make this method virtual. 
        // A derived class should not be able to override this method. 
        public void Dispose()
        {
            Dispose(true);
            // This object will be cleaned up by the Dispose method. 
            // Therefore, you should call GC.SupressFinalize to 
            // take this object off the finalization queue 
            // and prevent finalization code for this object 
            // from executing a second time.
            GC.SuppressFinalize(this);
        }

        // Dispose(bool disposing) executes in two distinct scenarios. 
        // If disposing equals true, the method has been called directly 
        // or indirectly by a user's code. Managed and unmanaged resources 
        // can be disposed. 
        // If disposing equals false, the method has been called by the 
        // runtime from inside the finalizer and you should not reference 
        // other objects. Only unmanaged resources can be disposed. 
        protected virtual void Dispose(bool disposing)
        {
            // Check to see if Dispose has already been called. 
            if(!this.disposed)
            {
                // If disposing equals true, dispose all managed 
                // and unmanaged resources. 
                if(disposing)
                {
                    // Dispose managed resources.
                    component.Dispose();
                }

                // Call the appropriate methods to clean up 
                // unmanaged resources here. 
                // If disposing is false, 
                // only the following code is executed.
                CloseHandle(handle);
                handle = IntPtr.Zero;

                // Note disposing has been done.
                disposed = true;

            }
        }

        // Use interop to call the method necessary 
        // to clean up the unmanaged resource.
        [System.Runtime.InteropServices.DllImport("Kernel32")]
        private extern static Boolean CloseHandle(IntPtr handle);

        // Use C# destructor syntax for finalization code. 
        // This destructor will run only if the Dispose method 
        // does not get called. 
        // It gives your base class the opportunity to finalize. 
        // Do not provide destructors in types derived from this class.
        ~MyResource()
        {
            // Do not re-create Dispose clean-up code here. 
            // Calling Dispose(false) is optimal in terms of 
            // readability and maintainability.
            Dispose(false);
        }
    }
    public static void Main()
    {
        // Insert code here to create 
        // and use the MyResource object.
    }
}

1

प्रबंधित संसाधनों के निपटान के लिए सबसे न्यायसंगत उपयोग मामला है, जीसी के लिए संसाधनों को पुनः प्राप्त करने की तैयारी है जो अन्यथा कभी एकत्र नहीं किए जाएंगे।

एक प्रमुख उदाहरण परिपत्र संदर्भ है।

Wh सर्पिल संदर्भों से बचने के लिए पैटर्न का उपयोग करना सबसे अच्छा अभ्यास है, यदि आप एक (बच्चे) वस्तु के साथ अंत करते हैं (उदाहरण के लिए) एक 'चाइल्ड' ऑब्जेक्ट जिसके पास उसके 'पैरेंट' के लिए एक संदर्भ है, तो यह अभिभावक के GC संग्रह को रोक सकता है यदि आप सिर्फ त्याग करते हैं संदर्भ और GC पर भरोसा - प्लस अगर आप एक अंतिम रूप से लागू किया है, यह कभी नहीं कहा जाएगा।

इसका एकमात्र तरीका यह है कि बच्चों पर अशक्त करने के लिए माता-पिता के संदर्भों को निर्धारित करके परिपत्र संदर्भों को मैन्युअल रूप से तोड़ दिया जाए।

माता-पिता और बच्चों पर आईडीआईसोपायरी को लागू करना ऐसा करने का सबसे अच्छा तरीका है। जब डिस्पोज़ को पैरेंट पर कॉल किया जाता है, तो सभी बच्चों पर डिस्पोज़ को कॉल करें, और चाइल्ड डिस्पोज़ मेथड में, पैरेंट संदर्भों को शून्य करने के लिए सेट करें।


4
अधिकांश भाग के लिए, GC मृत वस्तुओं की पहचान करके, बल्कि जीवित लोगों की पहचान करके काम नहीं करता है। प्रत्येक जीसी चक्र के बाद, प्रत्येक वस्तु के लिए जो अंतिम रूप देने के लिए पंजीकृत है, बड़े ऑब्जेक्ट के ढेर पर संग्रहीत है, या एक लाइव का लक्ष्य है WeakReference, सिस्टम एक ध्वज की जांच करेगा जो इंगित करता है कि पिछले जीसी चक्र में एक लाइव रूटेड संदर्भ पाया गया था , और या तो ऑब्जेक्ट को तुरंत अंतिम रूप देने की आवश्यकता वाली वस्तुओं की कतार में जोड़ देगा, ऑब्जेक्ट को बड़े ऑब्जेक्ट हीप से मुक्त करेगा, या कमजोर संदर्भ को अमान्य करेगा। यदि कोई अन्य रेफल्स मौजूद नहीं है, तो सर्कुलर रेफ ऑब्जेक्ट्स को जीवित नहीं रखेगा।
सुपरकट

1

मुझे लगता है कि प्रबंधित और अप्रबंधित संसाधनों दोनों के लिए आईडीसोपायरी का उपयोग करने के बारे में बात करने के लिए बहुत सारे उत्तर स्थानांतरित हो गए हैं। मैं इस लेख को सबसे अच्छे स्पष्टीकरणों में से एक के रूप में सुझाता हूं जो मैंने पाया है कि आईडीआईसोफाइल को वास्तव में कैसे उपयोग किया जाना चाहिए।

https://www.codeproject.com/Articles/29534/IDisposable-What-Your-Mother-Never-Told-You-About

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

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


1
मुझे समझ नहीं आया कि किसी ने आपके जवाब पर -1 क्यों रखा
सेबस्टियन ऑस्कर लोपेज
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.