c# - IDISposable इंटरफ़ेस का उचित उपयोग




.net garbage-collection (12)

मुझे एमएसडीएन दस्तावेज पढ़ने से पता है कि 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 द्वारा सामान्य रूप से इस्तेमाल किया जाता है?

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

https://code.i-harness.com


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

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

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

public void Cleanup()

public void Shutdown()

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

public void Dispose()

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

public interface IDisposable
{
   void Dispose()
}

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

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

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

क्या होगा यदि आपकी ऑब्जेक्ट ने 250 एमबी 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 विधि को कॉल करता है। जीसी आपकी निपटान विधि के बारे में नहीं जानता, या परवाह नहीं करता है। यह वह नाम था जिसे हमने एक विधि के लिए चुना था जिसे हम कॉल करते हैं जब हम अप्रबंधित सामान से छुटकारा पाने के लिए चाहते हैं।

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

नोट: सी # में, आप Finalize() विधि को ओवरराइड नहीं करते हैं। आप एक विधि लिखते हैं जो सी ++ विनाशक की तरह दिखता है , और संकलक इसे 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() देने के लिए एक तरीका है Finalize() को Dispose() कि किसी भी प्रबंधित संसाधन को स्पर्श नहीं करना चाहिए (क्योंकि वे अब और नहीं हो सकते हैं), जबकि अभी भी अप्रबंधित संसाधनों को मुक्त करना है।

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

इस आंतरिक विधि को "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() अपने कार्यान्वयन को बदलते हैं। 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 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 
   ...
}

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

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 लिए प्रलेखन। Object.Finalize कहता है:

ऑब्जेक्ट नष्ट होने से पहले वर्तमान ऑब्जेक्ट द्वारा आयोजित अप्रबंधित संसाधनों पर क्लीनअप ऑपरेशन करने के लिए अंतिम विधि का उपयोग किया जाता है।

लेकिन एमएसडीएन दस्तावेज भी IDisposable.Dispose लिए कहते हैं। IDisposable.Dispose :

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

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

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

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

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

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

इसके साथ समस्या यह है कि आपको पता नहीं है कि कचरा कलेक्टर आपके ऑब्जेक्ट को अंतिम रूप देने के लिए कब मिलेगा। आपके अन-प्रबंधित, गैर-आवश्यक, अप्रयुक्त देशी संसाधन तब तक चिपके रहेंगे जब तक कि कचरा कलेक्टर अंततः चलता न हो। फिर यह आपकी अंतिम विधि विधि को कॉल करेगा; अप्रबंधित संसाधनों की सफाई। ऑब्जेक्ट का दस्तावेज़ीकरण। इसे इंगित करें:

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

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

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

बोनस पढ़ना

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

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

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

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

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

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


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

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

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

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

ये कार्य राज्य परिवर्तनों का कारण बन सकते हैं जिन्हें स्वतंत्र रूप से अंतःस्थापित किया जा सकता है, या पूरी तरह से घोंसले की आवश्यकता हो सकती है। राज्य परिवर्तन थ्रेडसेफ हो सकता है, या वे शायद नहीं।

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

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

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

इसके बाद आपको Dispose का कोई मौका देने के लिए using कथन का using करना होगा। यह अनिवार्य रूप से स्टैक के साथ एक सवारी को घुमाने जैसा है (इसलिए फाइनलजर जीसी के लिए है, स्टैक के लिए using है)।

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

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

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

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 उसी उद्देश्य को पूरा करने के लिए using , सिवाय इसके कि अब आपको कॉलर का दुरुपयोग करने का कोई खतरा नहीं है। संसाधन को साफ करने में कोई रास्ता नहीं है।

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


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

Idiom मैं IDISposable लागू करने के लिए उपयोग ( थ्रेडसेफ नहीं ):

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
}

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

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

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

जीसी प्रदर्शन मीट्रिक प्रभावित होने का एकमात्र समय तब होता है जब एक [एसआईसी] जीसी.कोलेक्ट () को कॉल किया जाता है "

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

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

अब, सामान्य निष्पादन के दौरान अस्थायी संसाधनों को ठीक से साफ किया जाना चाहिए (जैसा कि @fezmonkey डेटाबेस कनेक्शन, सॉकेट, विंडो हैंडल को इंगित करता है ) अप्रबंधित स्मृति रिसाव से बचने के लिए। ये ऐसी चीजें हैं जिन्हें निपटान किया जाना है। If you create some class that owns a thread (and by owns I mean that it created it and therefore is responsible for ensuring it stops, at least by my coding style), then that class most likely must implement IDisposable and tear down the thread during Dispose .

The .NET framework uses the IDisposable interface as a signal, even warning, to developers that the this class must be disposed. I can't think of any types in the framework that implement IDisposable (excluding explicit interface implementations) where disposal is optional.


IDisposable अक्सर using कथन using फायदा उठाने के लिए 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.");
        }
    }
}

Apart from its primary use as a way to control the lifetime of system resources (completely covered by the awesome answer of Ian , kudos!), the IDisposable/using combo can also be used to scope the state change of (critical) global resources : the console , the threads , the process , any global object like an application instance .

I've written an article about this pattern: http://pragmateek.com/c-scope-your-global-state-changes-with-idisposable-and-the-using-statement/

It illustrates how you can protect some often used global state in a reusable and readable manner: console colors , current thread culture , Excel application object properties ...


I won't repeat the usual stuff about Using or freeing un-managed resources, that has all been covered. But I would like to point out what seems a common misconception.
Given the following code

Public Class LargeStuff
  Implements IDisposable
  Private _Large as string()

  'Some strange code that means _Large now contains several million long strings.

  Public Sub Dispose() Implements IDisposable.Dispose
    _Large=Nothing
  End Sub

I realise that the Disposable implementation does not follow current guidelines, but hopefully you all get the idea.
Now, when Dispose is called, how much memory gets freed?

Answer: None.
Calling Dispose can release unmanaged resources, it CANNOT reclaim managed memory, only the GC can do that. Thats not to say that the above isn't a good idea, following the above pattern is still a good idea in fact. Once Dispose has been run, there is nothing stopping the GC re-claiming the memory that was being used by _Large, even though the instance of LargeStuff may still be in scope. The strings in _Large may also be in gen 0 but the instance of LargeStuff might be gen 2, so again, memory would be re-claimed sooner.
There is no point in adding a finaliser to call the Dispose method shown above though. That will just DELAY the re-claiming of memory to allow the finaliser to run.


If anything, I'd expect the code to be less efficient than when leaving it out.

Calling the Clear() methods are unnecessary, and the GC probably wouldn't do that if the Dispose didn't do it...


In the example you posted, it still doesn't "free the memory now". All memory is garbage collected, but it may allow the memory to be collected in an earlier generation . You'd have to run some tests to be sure.

The Framework Design Guidelines are guidelines, and not rules. They tell you what the interface is primarily for, when to use it, how to use it, and when not to use it.

I once read code that was a simple RollBack() on failure utilizing IDisposable. The MiniTx class below would check a flag on Dispose() and if the Commit call never happened it would then call Rollback on itself. It added a layer of indirection making the calling code a lot easier to understand and maintain. The result looked something like:

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

    tx.Commit();
} 

I've also seen timing / logging code do the same thing. In this case the Dispose() method stopped the timer and logged that the block had exited.

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

So here are a couple of concrete examples that don't do any unmanaged resource cleanup, but do successfully used IDisposable to create cleaner code.


One problem with most discussions of "unmanaged resources" is that they don't really define the term, but seem to imply that it has something to do with unmanaged code. While it is true that many types of unmanaged resources do interface with unmanaged code, thinking of unmanaged resources in such terms isn't helpful.

Instead, one should recognize what all managed resources have in common: they all entail an object asking some outside 'thing' to do something on its behalf, to the detriment of some other 'things', and the other entity agreeing to do so until further notice. If the object were to be abandoned and vanish without a trace, nothing would ever tell that outside 'thing' that it no longer needed to alter its behavior on behalf of the object that no longer existed; consequently, the 'thing's usefulness would be permanently diminished.

An unmanaged resource, then, represents an agreement by some outside 'thing' to alter its behavior on behalf of an object, which would useless impair the usefulness of that outside 'thing' if the object were abandoned and ceased to exist. A managed resource is an object which is the beneficiary of such an agreement, but which has signed up to receive notification if it is abandoned, and which will use such notification to put its affairs in order before it is destroyed.


There are things that the Dispose() operation does in the example code that might have an effect that would not occur due to a normal GC of the MyCollection object.

If the objects referenced by _theList or _theDict are referred to by other objects, then that List<> or Dictionary<> object will not be subject to collection but will suddenly have no contents. If there were no Dispose() operation as in the example, those collections would still contain their contents.

Of course, if this were the situation I would call it a broken design - I'm just pointing out (pedantically, I suppose) that the Dispose() operation might not be completely redundant, depending on whether there are other uses of the List<> or Dictionary<> that are not shown in the fragment.


Yep, that code is completely redundant and unnecessary and it doesn't make the garbage collector do anything it wouldn't otherwise do (once an instance of MyCollection goes out of scope, that is.) Especially the .Clear() calls.

Answer to your edit: Sort of. If I do this:

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

It's functionally identical to this for purposes of memory management:

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

If you really really really need to free the memory this very instant, call GC.Collect() . There's no reason to do this here, though. The memory will be freed when it's needed.





idisposable