2010-11-23 14 views
5

एक स्थिर विश्लेषण उपकरण मुझे बताता रहता है कि मेरे सी # कोड में संसाधन रिसाव है।कचरा कलेक्टर कौन सा ऑब्जेक्ट साफ़ नहीं करता है?

StringReader reader = new StringReader(...); 

// do something with reader 

... 

} // static analysis tool cries that I've leaked **reader** 

मेरी उपकरण सही है:

यहाँ एक उदाहरण है? यदि हां, तो क्यों?

संपादित करें (टिप्पणी का जवाब) - मेरा स्थिर विश्लेषण उपकरण कहता है कि मुझे संसाधन लीक का एक गुच्छा मिला है। मुझे इस forum से पता है कि कुछ जावा एडब्ल्यूटी वस्तुओं को स्पष्ट रूप से मुक्त करने की आवश्यकता है, अन्यथा एक रिसाव होता है। क्या सी # ऑब्जेक्ट्स को स्पष्ट रूप से मुक्त करने की आवश्यकता है?

+0

स्थिर विश्लेषण उपकरण क्या है? क्या आप अधिक विशिष्ट – AlwaysAProgrammer

उत्तर

13

हाँ, आपका कोड बुरी तरह से लीक हो रहा है। यह इस तरह से होना चाहिए:

using (StringReader reader = new StringReader(...)) 
{ 

} 

हर वर्ग को लागू करने वाली IDisposable एक using block में लिपटे होने के लिए यह सुनिश्चित करें कि Dispose विधि हमेशा कहा जाता है की जरूरत है।


अद्यतन:

विस्तार से चर्चा करते: .NET में IDisposable इंटरफ़ेस जो निपटान पद्धति निर्धारित करता है नहीं है। कक्षाएं जो इस इंटरफ़ेस को कार्यान्वित करती हैं (जैसे फाइल स्ट्रीम, डेटाबेस कनेक्शन, पाठक, ...) में अप्रबंधित संसाधनों के लिए पॉइंटर्स हो सकते हैं और यह सुनिश्चित करने का एकमात्र तरीका है कि उन अप्रबंधित संसाधन/हैंडल मुक्त हैं, निपटान विधि को कॉल करना है। तो .NET में सुनिश्चित करने के लिए कुछ कोड कहा जाता है कि एक अपवाद फेंक दिया जाता है एक कोशिश/अंत में कथन का उपयोग करने के लिए है, भले ही:

var myRes = new MyResource(); // where MyResource implements IDisposable 
try 
{ 
    myRes.DoSomething(); // this might throw an exception 
} 
finally 
{ 
    if (myRes != null) 
    { 
     ((IDisposable)myRes).Dispose(); 
    } 
} 

सी # कोड लिखने लोग जल्दी से पता चला है कि यह हर बार जब आप एक साथ काम कर रहा था लेखन डिस्पोजेबल संसाधन एक पिटा था।

using (var myRes = new MyResource()) 
{ 
    myRes.DoSomething(); // this might throw an exception 
} 

जो थोड़े कम है: तो वे using बयान पेश किया है।

+0

डारिन, क्या आप कृपया अपने कोड की व्याख्या कर सकते हैं? मैं एक सी ++ पृष्ठभूमि से आया हूँ। धन्यवाद। –

+0

यह लीक हो रहा है, लेकिन कचरा कलेक्टर इसे एक मुद्दा बनने से पहले इसका ख्याल रखेगा। हालांकि, सलाह अभी भी अच्छी है। –

+2

आप कहते हैं कि यह "बुरी तरह" लीक कर रहा है - लेकिन 'स्ट्रिंग रीडर' के मामले में, वास्तव में कुछ भी लीक नहीं होगा - यह उस सम्मान में 'मेमोरीस्ट्रीम' जैसा है। वैसे भी इसका निपटान करना सबसे अच्छा है, केवल सर्वोत्तम अभ्यास के लिए और यदि आपने कभी भी कुछ ऐसा करने के लिए कोड को बदल दिया है जिसे * सफाई * की आवश्यकता है ... लेकिन यह वास्तव में लीक नहीं है। –

0

आपने लीक किया है, लेकिन 'आखिरकार' जीसी आपके लिए इसे साफ कर देगा।

+0

हो सकते हैं आप इसे किसी भी गैर-स्पष्ट रूप से हटाए गए ऑब्जेक्ट के बारे में कह सकते हैं, हालांकि ... – Cameron

1

मेरा मानना ​​है कि यह बाद आप इसके साथ समाप्त किया है क्योंकि आप Close विधि कहा जाता है नहीं किया है, MSDN के अनुसार, हालांकि है:

बंद के इस कार्यान्वयन कॉल निपटान विधि एक सही मूल्य गुजर।

तो मैं उम्मीद करता हूं कि जब कचरा कलेक्टर पाठक के पास हो जाता है, तो इसे उसी अंत परिणाम (और कोई स्मृति रिसाव) के साथ नहीं छोड़ा जाएगा।

अद्यतन: मैं गलत कर रहा हूँ, जीसी नहीं स्वचालित रूप से IDisposable वस्तुओं फेंक करता है। आपको स्पष्ट रूप से बंद (या निपटान) को कॉल करने की आवश्यकता है।

+0

यदि 'IDISposable' पैटर्न सही ढंग से कार्यान्वित किया गया है, तो क्लास फ़ाइनलाइज़र (' ~ कक्षा') _will_ चलाया जाना चाहिए, 'निपटान' को कॉल करने के समान प्रभाव। बेशक, इसके मुकाबले इसके लिए और भी कुछ है, जिसमें मेरे पास यहां व्याख्या करने के लिए पर्याप्त जगह नहीं है। –

0

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

उपयोग कथन में देखने का प्रयास करें और यह आपके लिए स्वचालित रूप से निपटान करेगा।

using (sr) { 
// your code 
} 
+0

एक स्ट्रिंग्रेडर स्ट्रीम तक नहीं पहुंच पाएगा। –

2

ऐसा लगता है कि आप अपने स्ट्रिंग रीडर का निपटान नहीं कर रहे हैं। अप्रबंधित संसाधनों को साफ करने के लिए आपको .Dispose() पर कॉल करने की आवश्यकता है। स्वचालित रूप से ब्लॉक के अंत में भले ही आपके कोड एक अपवाद (एक अंत में ब्लॉक का उपयोग करने के लिए समान) फेंकता

using (StringReader reader = new StringReader(...)) 
{ 
    // your code 
} 

यह निपटान (कारण होगा),: या बेहतर अभी तक, यह एक using ब्लॉक में इस तरह के रूप का उपयोग करें।

0

कचरा कलेक्टर कुछ भी एकत्र करेगा जो अब इसका संदर्भ नहीं रखता है। आपके नमूने में, reader अंततः एकत्र किया जाएगा (हालांकि, कोई भी कब बता सकता है)।

हालांकि, 'स्थैतिक विश्लेषण उपकरण' शिकायत कर रहा है कि आप मैन्युअल रूप से Dispose() पर कॉल नहीं कर रहे हैं।

StringReader reader = ... 
... 
reader.Dispose(); 

इस विशिष्ट मामले में, यह शायद एक बड़ा सौदा नहीं है। हालांकि, कई आईओ कक्षाओं (* स्ट्रीम, * रीडर, आदि) से निपटने के दौरान, जब आप पूरा कर लें तो उनका निपटान करना अच्छा होता है। आप मदद करने के लिए using उपयोग कर सकते हैं:

using(StringReader reader = ...) { 
    ... 
} //reader is automatically disposed here 
6

आपका कोड वास्तव में इस विशिष्ट मामले में कुछ भी लीक नहीं है, क्योंकि StringReader वास्तव में साफ करने के लिए किसी भी संसाधन नहीं है, MemoryStream जैसे नहीं करता है। (MemoryStream के साथ आप अभी भी आप इसे एसिंक्रोनस रूप से उपयोग कर रहा है या यह दूरस्थ बनाने के कर रहे हैं तो यह के निपटान के लिए की आवश्यकता होगी, समाप्त कर सकते हैं ... लेकिन सीधा मामलों में यह बात नहीं है।)

हालांकि, यह करने के लिए एक अच्छा विचार है सिद्धांत पर केवल IDisposable लागू करने वाली किसी भी चीज़ का निपटान करें। इससे आपको लीकिंग (शायद अस्थायी रूप से) अप्रबंधित संसाधन हैंडल जैसे संसाधनों से बचने से बचाएगा। आप बंद नहीं कर सकते हैं या यहाँ reader निपटान (एक finally ब्लॉक में या एक using statement के माध्यम से) यह जो कुछ भी प्रकार जब तक फ़ाइल खुला का आयोजन करेगा तो

StreamReader reader = new StreamReader("file.txt"); 
... 

:

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

2

जैसा कि अन्य ने कहा है, यह स्ट्रिंग रीडर को डिस्पोजेड नहीं कर रहा है, इसलिए मैं उस पर हिट नहीं करूंगा।

क्या चल रहा है यह है कि स्थिर विश्लेषण उपकरण अनिवार्य रूप से एक गूंगा उपकरण है। और मेरा मतलब यह नहीं है कि इसका उपयोग न करें, मेरा मतलब है गूंगा क्योंकि इसमें बहुत सीमित मानदंड दिख रहे हैं।

इस मामले में यह एक वस्तु को तुरंत चालू किया जाता है जिसका वर्ग IDISposable लागू करता है। टूल तब देख रहा है कि ऑब्जेक्ट गुंजाइश से बाहर होने से पहले आप एक संबंधित निपटान कॉल करते हैं या नहीं। यह स्पष्ट रूप से ऑब्जेक्ट कहकर बनाया जा सकता है।(); या उपयोग के माध्यम से (var x = ...) {} खंड।

MS specs के अनुसार, कक्षाओं को अप्रबंधित संसाधनों (जैसे फ़ाइल हैंडल) से निपटने की स्थिति में IDISposable लागू करना चाहिए। अब, आप इस MSDN post की समीक्षा करना चाहेंगे जो इस बात के बारे में बात करता है कि कौन से वर्ग IDISposable को लागू करते हैं, जो कि में को निपटान() चालू करने के लिए नहीं है।

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

अन्य चेतावनियों को अनदेखा करने के लिए आपके स्थिर विश्लेषण उपकरण (यदि संभव हो) को कॉन्फ़िगर करना होगा। मुझे सच में लगता है कि यह एक बुरा विचार होगा (टीएम)

2

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

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

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