कचरा संग्रह से निपटान को अलग करना महत्वपूर्ण है। वे पूरी तरह से अलग चीजें हैं, एक बिंदु में आम है जो मैं एक मिनट में आऊंगा।
Dispose
, कचरा संग्रहण और अंतिम रूप दिए जाने
जब आप एक using
बयान लिखने, यह बस वाक्यात्मक चीनी एक कोशिश/अंत में ब्लॉक के लिए है ताकि Dispose
कहा जाता है, भले ही using
बयान के शरीर में कोड फेंकता एक अपवाद। यह का अर्थ यह नहीं है कि वस्तु ब्लॉक के अंत में कचरा एकत्रित है।
निपटान अप्रबंधित संसाधन (गैर-स्मृति संसाधन) है। ये यूआई हैंडल, नेटवर्क कनेक्शन, फाइल हैंडल इत्यादि हो सकते हैं। ये सीमित संसाधन हैं, इसलिए आप उन्हें जितनी जल्दी हो सके उन्हें छोड़ना चाहते हैं। आपको IDisposable
लागू करना चाहिए जब भी आपका प्रकार एक अप्रबंधित संसाधन "मालिक" हो, सीधे (आमतौर पर IntPtr
के माध्यम से) या अप्रत्यक्ष रूप से (उदा। Stream
, SqlConnection
आदि के माध्यम से)।
कचरा संग्रह केवल स्मृति के बारे में है - एक छोटी मोड़ के साथ। कचरा कलेक्टर उन वस्तुओं को खोजने में सक्षम है जिन्हें अब संदर्भित नहीं किया जा सकता है, और उन्हें मुक्त कर सकते हैं। यह हर समय कचरे की तलाश नहीं करता है - केवल तभी जब यह पता चलता है कि इसकी आवश्यकता है (उदाहरण के लिए यदि ढेर का एक "पीढ़ी" स्मृति से बाहर हो जाता है)।
मोड़ अंतिमकरण है। कचरा कलेक्टर उन ऑब्जेक्ट्स की एक सूची रखता है जो अब तक पहुंचने योग्य नहीं हैं, लेकिन जिनके पास अंतिम रूप है (सी # में ~Foo()
के रूप में लिखा गया है, कुछ हद तक भ्रमित - वे सी ++ विनाशकों की तरह कुछ नहीं हैं)। यह इन वस्तुओं पर फाइनलाइज़र चलाता है, बस अगर उनकी याददाश्त मुक्त होने से पहले उन्हें अतिरिक्त सफाई करने की आवश्यकता होती है।
फ़ाइनलाइज़र लगभग हमेशा उस मामले में संसाधनों को साफ करने के लिए उपयोग किए जाते हैं जहां प्रकार का उपयोगकर्ता व्यवस्थित ढंग से इसका निपटान करने के लिए भूल गया है। तो यदि आप FileStream
खोलते हैं लेकिन Dispose
या Close
पर कॉल करना भूल जाते हैं, तो अंतिम अंततः आपके लिए अंतर्निहित फ़ाइल हैंडल जारी करेगा। एक अच्छी तरह से लिखित कार्यक्रम में, फाइनलरों को मेरी राय में लगभग कभी नहीं आग लगनी चाहिए।
null
करने के लिए एक चर की स्थापना पर null
एक छोटी सी बात करने के लिए एक चर सेट करना - यह लगभग कचरा संग्रहण के लिए आवश्यक कभी नहीं किया गया है। यदि आप एक सदस्य चर है, तो आप कभी-कभी ऐसा करना चाहते हैं, हालांकि मेरे अनुभव में किसी ऑब्जेक्ट के "भाग" के लिए दुर्लभ होना आवश्यक नहीं है। जब यह एक स्थानीय चर है, तो यह जानने के लिए कि जब आप किसी संदर्भ का उपयोग नहीं करेंगे तो JIT आमतौर पर पर्याप्त (रिलीज़ मोड में) स्मार्ट होगा। उदाहरण के लिए:
StringBuilder sb = new StringBuilder();
sb.Append("Foo");
string x = sb.ToString();
// The string and StringBuilder are already eligible
// for garbage collection here!
int y = 10;
DoSomething(y);
// These aren't helping at all!
x = null;
sb = null;
// Assume that x and sb aren't used here
एक बार जहां यह null
के लिए एक स्थानीय चर स्थापित कर रही है जब आप एक पाश में हैं, और पाश की कुछ शाखाओं चर का उपयोग करने की जरूरत है, लेकिन आप क्या आप जानते हैं लायक हो सकता है एक बिंदु पर पहुंचा है जिस पर आप नहीं करते हैं। उदाहरण के लिए:
SomeObject foo = new SomeObject();
for (int i=0; i < 100000; i++)
{
if (i == 5)
{
foo.DoSomething();
// We're not going to need it again, but the JIT
// wouldn't spot that
foo = null;
}
else
{
// Some other code
}
}
कार्यान्वयन IDisposable/finalizers
तो, अपने स्वयं के प्रकार finalizers को लागू करना चाहिए? लगभग निश्चित रूप से नहीं। यदि आप केवल परोक्ष रूप से अप्रबंधित संसाधन (उदा।आपके पास सदस्य चर के रूप में FileStream
है) फिर अपना स्वयं का फ़ाइनलाइज़र जोड़ने में मदद नहीं करेगा: आपकी ऑब्जेक्ट होने पर धारा लगभग निश्चित रूप से कचरा संग्रह के लिए योग्य होगी, इसलिए आप केवल अंतिम बारिश करने वाले FileStream
पर भरोसा कर सकते हैं (यदि आवश्यक हो - यह कुछ और, आदि का उल्लेख कर सकता है)। यदि आप एक अप्रबंधित संसाधन "लगभग" सीधे पकड़ना चाहते हैं, तो SafeHandle
आपका मित्र है - इसमें जाने में थोड़ा समय लगता है, लेकिन इसका मतलब है कि आप almostnever need to write a finalizer again देखेंगे। यदि आपको संसाधन (वास्तव में IntPtr
) पर वास्तव में प्रत्यक्ष संभाल है तो आपको केवल अंतिम रूप देने की आवश्यकता होनी चाहिए और आपको जितनी जल्दी हो सके SafeHandle
पर जाना चाहिए। (वहां दो लिंक हैं - आदर्श रूप से पढ़ें।)
जो डफी के पास very long set of guidelines around finalizers and IDisposable (बहुत से स्मार्ट लोक के साथ सह-लिखित) है जो पढ़ने योग्य हैं। यह जानना उचित है कि यदि आप अपनी कक्षाओं को सील करते हैं, तो यह जीवन को बहुत आसान बनाता है: Dispose
ओवरराइड करने का पैटर्न एक नया आभासी Dispose(bool)
विधि इत्यादि को कॉल करने के लिए केवल तभी प्रासंगिक होता है जब आपकी कक्षा विरासत के लिए डिज़ाइन की जाती है।
यह एक पर्यटन का एक सा है, लेकिन स्पष्टीकरण के लिए कहें आप जहां चाहें कुछ :)
पुन "एक बार जहां स्थानीय चर को शून्य करने के लायक हो सकता है" - शायद कुछ कांटेदार "कैप्चर" परिदृश्य (समान चर के एकाधिक कैप्चर) - लेकिन यह पोस्ट को जटिल बनाने के लायक नहीं हो सकता है! +1 ... –
@Marc: यह सच है - मैंने कब्जे वाले चर के बारे में भी सोचा नहीं था। हम्म। हाँ, मुझे लगता है कि मैं अकेला छोड़ दूंगा;) –
वाह। मैं अंततः स्कीटिस्ट्स की पंथ के स्रोत को समझता हूं। यह पोस्ट कमाल है! – JohnFx