"मेमोरी लीक" का एनाटॉमी


172

.NET परिप्रेक्ष्य में:

  • स्मृति रिसाव क्या है ?
  • आप यह कैसे निर्धारित कर सकते हैं कि आपका आवेदन लीक हुआ है या नहीं? प्रभाव क्या हैं?
  • आप स्मृति रिसाव को कैसे रोक सकते हैं?
  • यदि आपके आवेदन में मेमोरी लीक है, तो जब यह प्रक्रिया बाहर निकलती है या मार दी जाती है, तो क्या वह चली जाती है? या क्या आपके आवेदन में मेमोरी लीक प्रक्रिया पूरी होने के बाद भी सिस्टम पर अन्य प्रक्रियाओं को प्रभावित करती है?
  • और COM इंटरोप और / या P / Invoke के माध्यम से अप्रबंधित कोड के बारे में क्या पता चला है?

जवाबों:


110

सबसे अच्छी व्याख्या जो मैंने देखी है, वह प्रोग्रामिंग ई-बुक के मुफ्त फाउंडेशनों के अध्याय 7 में है ।

मूल रूप से, .NET में स्मृति रिसाव तब होता है जब संदर्भित ऑब्जेक्ट निहित होते हैं और इस तरह कचरा एकत्र नहीं किया जा सकता है। यह आकस्मिक रूप से तब होता है जब आप इच्छित दायरे से परे संदर्भों पर पकड़ रखते हैं।

आपको पता चलेगा कि आपके पास लीक है जब आपको आउटऑफमेरी एक्सिडेंस मिलना शुरू होता है या आपकी मेमोरी का उपयोग उस सीमा से अधिक हो जाता है, जिसकी आप अपेक्षा करते हैं ( PerfMon की अच्छी मेमोरी काउंटर होती है)।

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

बेशक, एक अच्छी मेमोरी प्रोफाइल आपको अपनी ऑब्जेक्ट रेखांकन देखने और अपनी वस्तुओं के घोंसले के शिकार / संदर्भ का पता लगाने के लिए यह देखने के लिए कि संदर्भ कहां से आ रहे हैं और कौन सी जड़ वस्तु जिम्मेदार है ( लाल-गेट चींटियों की प्रोफाइल , JetBrains dotMemory, memprofiler वास्तव में अच्छे हैं विकल्प, या आप केवल-पाठ WinDbg और SOS का उपयोग कर सकते हैं , लेकिन जब तक आप एक वास्तविक गुरु नहीं हो जाते हैं, मैं एक वाणिज्यिक / दृश्य उत्पाद की जोरदार सिफारिश करूंगा।

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


11
ओह, आपको पुस्तक पसंद है? मैंने देखा है कि लेखक समय-समय पर स्टैकओवरफ्लो पर पॉप अप करता है।
जॉननो नोलन

कुछ .NET ऑब्जेक्ट्स खुद को रूट कर सकते हैं और अचूक हो सकते हैं। इस कारण से कुछ भी IDisposable को निपटाया जाना चाहिए।
कियूरू

1
@kyoryu: कोई वस्तु अपने आप कैसे होती है?
आंद्रेई रोनेया

2
@Andrei: मुझे लगता है कि एक रनिंग थ्रेड शायद किसी वस्तु को स्वयं जड़ने का सबसे अच्छा उदाहरण है। एक ऐसी वस्तु जो स्थैतिक गैर-सार्वजनिक स्थान पर खुद को संदर्भित करती है (जैसे स्थैतिक घटना की सदस्यता लेना, या स्थैतिक क्षेत्र आरंभीकरण द्वारा एक सिंगलटन को लागू करना) के रूप में अच्छी तरह से खुद को निहित किया जा सकता है, क्योंकि कोई स्पष्ट तरीका नहीं है ... उम ... "इसे उखाड़ फेंकना"।
जेफरी हंटिन

@ जेफ़्री यह एक अनौपचारिक तरीका है कि व्हाट्सएप हो रहा है और मुझे यह पसंद है!
Exitos

35

कड़ाई से बोलने पर, एक स्मृति रिसाव मेमोरी का उपभोग कर रहा है जो प्रोग्राम द्वारा "अब उपयोग नहीं किया जाता है" है।

"अब उपयोग नहीं किया गया" का एक से अधिक अर्थ है, इसका अर्थ "इससे अधिक संदर्भ नहीं हो सकता है", अर्थात, पूरी तरह से अपरिवर्तनीय है, या इसका मतलब हो सकता है, संदर्भित, पुनर्प्राप्त करने योग्य, अप्रयुक्त लेकिन प्रोग्राम वैसे भी संदर्भ रखता है। केवल बाद में पूरी तरह से प्रबंधित वस्तुओं के लिए .Net पर लागू होता है । हालांकि, सभी वर्ग सही नहीं हैं और कुछ बिंदु पर एक अंतर्निहित अप्रबंधित कार्यान्वयन उस प्रक्रिया के लिए स्थायी रूप से संसाधनों को लीक कर सकता है।

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

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

अधिकांश लीक के लिए, प्रक्रिया समाप्त होने पर संसाधन पुनर्प्राप्त किए जाते हैं, हालांकि कुछ सटीक मामलों में कुछ संसाधन हमेशा पुनर्प्राप्त नहीं किए जाते हैं, इसके लिए GDI कर्सर हैंडल कुख्यात हैं। बेशक, यदि आपके पास एक इंटरप्रोसेस संचार तंत्र है, तो दूसरी प्रक्रिया में आवंटित मेमोरी को तब तक मुक्त नहीं किया जाएगा, जब तक कि यह प्रक्रिया उसे मुक्त या समाप्त नहीं कर देती।


32

मुझे लगता है कि "एक मेमोरी लीक क्या है" और "क्या प्रभाव हैं" सवालों के जवाब पहले से ही अच्छी तरह से दिए गए हैं, लेकिन मैं अन्य सवालों पर कुछ और चीजें जोड़ना चाहता था ...

कैसे समझें कि आपका आवेदन लीक हुआ है या नहीं

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

कैसे बचाना है

अन्य अच्छी राय दी गई है। मैं सिर्फ यह जोड़ना चाहूंगा कि शायद .NET मेमोरी लीक का सबसे आम तौर पर अनदेखा कारण इवेंट हैंडलर को ऑब्जेक्ट से हटाए बिना उन्हें जोड़ना है। किसी वस्तु से जुड़ा एक घटना हैंडलर उस वस्तु के संदर्भ का एक रूप है, इसलिए अन्य सभी संदर्भ चले जाने के बाद भी संग्रह को रोका जा सकेगा। हमेशा ईवेंट हैंडलर को अलग करना याद रखें ( -=C # में सिंटैक्स का उपयोग करके )।

जब प्रक्रिया से बाहर निकलता है, तो क्या रिसाव खत्म हो जाता है, और COM इंटरॉप के बारे में क्या?

जब आपकी प्रक्रिया समाप्त हो जाती है, तो सभी पता स्थान में मैप की गई मेमोरी OS द्वारा पुनः प्राप्त कर ली जाती है, जिसमें DLL से प्राप्त की गई कोई COM वस्तु भी शामिल होती है। तुलनात्मक रूप से शायद ही कभी, COM वस्तुओं को अलग-अलग प्रक्रियाओं से परोसा जा सकता है। इस मामले में, जब आपकी प्रक्रिया समाप्त हो जाती है, तो आप अभी भी आपके द्वारा उपयोग की जाने वाली किसी भी COM सर्वर प्रक्रियाओं में आवंटित मेमोरी के लिए जिम्मेदार हो सकते हैं।


19

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

मुझे व्यक्तिगत रूप से आउट ऑफ मेमोरी एक्सेलेरेशन का सामना करना पड़ा है जो कि हो सकता है लेकिन डॉट नेट एप्लिकेशन में मेमोरी लीक के लिए अनन्य नहीं हैं। (OOM पिनिंग आर्टिकल पिनिंग आर्टिकल से भी आ सकता है )। यदि आपको OOM त्रुटियां नहीं मिल रही हैं या यह पुष्टि करने की आवश्यकता है कि क्या यह मेमोरी लीक है, तो यह आपके आवेदन को प्रोफाइल करने का एकमात्र तरीका है।

मैं भी कोशिश करूँगा और निम्नलिखित सुनिश्चित करूँगा:

क) सब कुछ जो इडीसोपायरी को लागू करता है, या तो अंततः ब्लॉक का उपयोग करके निपटाया जाता है या स्टेटमेंट का उपयोग करता है जिसमें ब्रश, पेन आदि शामिल हैं (कुछ लोग इसके अलावा कुछ भी नहीं करने के लिए सब कुछ सेट करने का तर्क देते हैं)

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

ग) यदि आप मानवरहित कोड / विंडोज़ एपीआई का उपयोग कर रहे हैं, तो इनसे सही तरीके से निपटा जा सकता है। (कुछ के पास संसाधन जारी करने के तरीके साफ हैं)

उम्मीद है की यह मदद करेगा।


19

यदि आपको .NET में मेमोरी लीक का निदान करना है, तो इन लिंक की जाँच करें:

http://msdn.microsoft.com/en-us/magazine/cc163833.aspx

http://msdn.microsoft.com/en-us/magazine/cc164138.aspx

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

Microsoft के पास एक नया उपकरण भी है जो क्रैश डंप को उत्पन्न करने में सहायता करता है, ADPlus को बदलने के लिए, जिसे DebugDiag कहा जाता है।

http://www.microsoft.com/downloads/details.aspx?FamilyID=28bd5941-c458-46f1-b24d-f60151d875a3&displaylang=en


16

Microsoft से CLR प्रोफाइलर का उपयोग करना http://www.microsoft.com/downloads/details.aspx?familyid=86ce6052-d7f4-4aeb-9b7a-94635beebdda&disnlang=en यह निर्धारित करने का एक शानदार तरीका है कि कौन सी वस्तुएं स्मृति को धारण कर रही हैं, क्या निष्पादन प्रवाह का नेतृत्व करता है। इन वस्तुओं के निर्माण के लिए, और यह भी निगरानी करना कि कौन सी वस्तुएं ढेर पर रहती हैं (विखंडन, LOH, आदि)।


15

C # किताब, (Ch। 20) के माध्यम से जेफ रिचर्स सीएलआर में कचरा इकट्ठा करने वाले का काम कैसे होता है, इसका सबसे अच्छा विवरण । इसे पढ़ने से यह समझने में मदद मिलती है कि वस्तुएं कैसे बनी रहती हैं।

किसी वस्तु को जड़ से उखाड़ने के सबसे आम कारणों में से एक है, घटनाओं को एक वर्ग से दूर करना। यदि आप किसी बाहरी घटना को अंजाम देते हैं

जैसे

SomeExternalClass.Changed += new EventHandler(HandleIt);

और जब आप निपटाने के लिए इसे अनहुक करना भूल जाते हैं, तो SomeExternalClass का आपकी कक्षा में एक रेफरी होता है।

जैसा कि ऊपर उल्लेख किया गया है, SciTech मेमोरी प्रोफाइल आपको उन वस्तुओं की जड़ों को दिखाने में उत्कृष्ट है , जिन पर आपको संदेह है।

लेकिन एक विशेष प्रकार की जांच करने का एक बहुत ही त्वरित तरीका भी है बस WnDBG का उपयोग करें (संलग्न करते समय आप VS.NET तत्काल विंडो में भी इसका उपयोग कर सकते हैं):

.loadby sos mscorwks
!dumpheap -stat -type <TypeName>

अब कुछ ऐसा करें जो आपको लगता है कि उस प्रकार की वस्तुओं का निपटान करेगा (जैसे एक विंडो बंद करें)। यहाँ पर डिबग बटन लगाना आसान है जो System.GC.Collect()एक दो बार चलेगा ।

फिर चला !dumpheap -stat -type <TypeName>। यदि संख्या कम नहीं हुई, या आप उम्मीद के मुताबिक नीचे नहीं गए हैं, तो आपके पास आगे की जांच के लिए एक आधार है। ( इंगो राममेर द्वारा दिए गए एक सेमिनार से मुझे यह टिप मिली )।


14

मैं एक प्रबंधित वातावरण में अनुमान लगाता हूं, एक लीक होगा कि आप स्मृति के एक बड़े हिस्से के लिए एक अनावश्यक संदर्भ रख पाएंगे।


11

लोग क्यों सोचते हैं कि .NET में एक मेमोरी लीक किसी अन्य लीक के समान नहीं है?

स्मृति रिसाव तब होता है जब आप किसी संसाधन से जुड़ते हैं और उसे जाने नहीं देते हैं। आप यह प्रबंधित और अप्रबंधित कोडिंग दोनों में कर सकते हैं।

.NET, और अन्य प्रोग्रामिंग टूल्स के बारे में, कचरा इकट्ठा करने और स्थितियों को कम करने के अन्य तरीकों के बारे में विचार हैं जो आपके आवेदन को लीक कर देंगे। लेकिन मेमोरी लीक को रोकने का सबसे अच्छा तरीका यह है कि आपको अपने अंतर्निहित मेमोरी मॉडल को समझने की जरूरत है, और आप जिस प्लेटफॉर्म का उपयोग कर रहे हैं, वह कैसे काम करता है।

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

अप्रबंधित कोडिंग करते समय, आप सामान्य रूप से सफाई करना सुनिश्चित करते हैं, आप जानते हैं कि आप जिन संसाधनों को पकड़ते हैं, उनकी सफाई आपकी जिम्मेदारी होगी, न कि चौकीदार की।

दूसरी ओर .NET में, बहुत सारे लोग सोचते हैं कि GC सब कुछ साफ कर देगा। ठीक है, यह आपके लिए कुछ करता है, लेकिन आपको यह सुनिश्चित करने की आवश्यकता है कि ऐसा है। .NET बहुत सी चीजों को लपेटता है, इसलिए आप हमेशा यह नहीं जानते हैं कि क्या आप एक प्रबंधित या अप्रबंधित संसाधन के साथ काम कर रहे हैं, और आपको यह सुनिश्चित करने की आवश्यकता है कि आप क्या काम कर रहे हैं। फ़ॉन्ट, GDI संसाधन, सक्रिय निर्देशिका, डेटाबेस आदि को हैंडल करना आमतौर पर ऐसी चीजें हैं जिनकी आपको आवश्यकता होती है।

प्रबंधित शर्तों में, मैं यह कहने के लिए अपनी गर्दन को लाइन पर रखूंगा कि प्रक्रिया के मारे जाने / हटाए जाने के बाद वह चली जाएगी।

मुझे लगता है कि बहुत से लोगों के पास यह है, और मुझे उम्मीद है कि यह समाप्त हो जाएगा। आप अपने गंदगी को साफ करने के लिए उपयोगकर्ता को अपना ऐप समाप्त करने के लिए नहीं कह सकते हैं! एक ब्राउज़र पर नज़र डालें, जो IE, FF आदि हो सकता है, फिर खोलें, कहें, Google रीडर, इसे कुछ दिनों के लिए रहने दें, और देखें कि क्या होता है।

यदि आप फिर ब्राउज़र में एक और टैब खोलते हैं, कुछ साइट पर सर्फ करते हैं, तो उस टैब को बंद करें जिसने दूसरे पेज को होस्ट किया है जो ब्राउज़र को लीक करता है, क्या आपको लगता है कि ब्राउज़र मेमोरी को रिलीज़ करेगा? आईई के साथ ऐसा नहीं है। यदि मैं Google रीडर का उपयोग करता हूं, तो मेरे कंप्यूटर पर IE कम समय में (लगभग 3-4 दिन) 1 गिबी मेमोरी आसानी से खा जाएगा। कुछ हेडसेट्स और भी खराब हैं।


10

मैं एक प्रबंधित वातावरण में अनुमान लगाता हूं, एक लीक होगा कि आप स्मृति के एक बड़े हिस्से के लिए एक अनावश्यक संदर्भ रख पाएंगे।

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

StreamReader sr;
using(sr = new StreamReader("somefile.txt"))
{
    //do some stuff
}

और यदि आप एक ऐसा वर्ग बनाते हैं, जो अप्रबंधित वस्तुओं का उपयोग कर रहा है, यदि आप सही ढंग से आईडीसिसोपयोगी नहीं कर रहे हैं, तो आप अपने वर्ग के उपयोगकर्ताओं के लिए मेमोरी लीक का कारण बन सकते हैं।


9

सभी स्मृति लीक को कार्यक्रम समाप्ति के द्वारा हल किया जाता है।

पर्याप्त मेमोरी और ऑपरेटिंग सिस्टम आपकी ओर से समस्या को हल करने का निर्णय ले सकते हैं।


8

मैं बर्नार्ड के साथ इस तरह से सहमति बनाऊंगा कि एक मेम लीक क्या होगा।

आप इसके स्मृति उपयोग को देखने के लिए अपने आवेदन को प्रोफाइल कर सकते हैं, और यह निर्धारित कर सकते हैं कि यदि इसकी मेमोरी बहुत अधिक है जब यह नहीं होना चाहिए तो आप कह सकते हैं कि इसमें रिसाव है।

प्रबंधित शर्तों में, मैं यह कहने के लिए अपनी गर्दन को लाइन पर रखूंगा कि प्रक्रिया के मारे जाने / हटाए जाने के बाद वह चली जाएगी।

मानव रहित कोड इसका अपना जानवर है और यदि कोई रिसाव इसके भीतर मौजूद है, तो यह एक मानक मेम का पालन करेगा। रिसाव की परिभाषा।


7

यह भी ध्यान रखें कि .NET के दो ढेर हैं, एक बड़ी वस्तु का ढेर है। मेरा मानना ​​है कि इस ढेर पर लगभग or५ k या उससे बड़ी वस्तुओं को रखा जाता है। इस ढेर में नियमित ढेर से अलग जीवनकाल के नियम हैं।

यदि आप बड़े मेमोरी स्ट्रक्चर (डिक्शनरी या लिस्ट) बना रहे हैं, तो यह देखना उचित होगा कि सटीक नियम क्या हैं।

जहाँ तक मेमोरी को प्रोसेस समाप्ति पर पुनः प्राप्त करने की बात है, जब तक कि आपका रनिंग Win98 या इसके समतुल्य नहीं है, तब तक सबकुछ समाप्ति के बाद OS पर वापस आ जाता है। एकमात्र अपवाद वे चीजें हैं जो क्रॉस-प्रोसेस खोली जाती हैं और एक अन्य प्रक्रिया में अभी भी संसाधन खुला है।

COM ऑब्जेक्ट्स मुश्किल हो सकता है। यदि आप हमेशा IDisposeपैटर्न का उपयोग करते हैं , तो आप सुरक्षित रहेंगे। लेकिन मैं कुछ इंटरोप असेंबली में लागू करता हूं जो लागू होते हैं IDisposeMarshal.ReleaseCOMObjectजब आप इसके साथ काम कर रहे होते हैं, तो यहां कॉल करना महत्वपूर्ण होता है। COM ऑब्जेक्ट अभी भी मानक COM संदर्भ गणना का उपयोग करते हैं।


6

मैंने पाया है कि .Net मेमोरी प्रोफाइलर को .Net में मेमोरी लीक खोजने पर बहुत अच्छी मदद मिलती है। यह Microsoft CLR प्रोफाइलर की तरह मुफ़्त नहीं है, लेकिन मेरी राय में इस बिंदु पर तेज़ और अधिक है। ए


1

एक परिभाषा यह है: अप्राप्य मेमोरी को रिलीज़ करने में असमर्थ, जो अब आवंटन प्रक्रिया के निष्पादन के दौरान नई प्रक्रिया को आवंटित नहीं किया जा सकता है। यह ज्यादातर जीसी तकनीकों का उपयोग करके या स्वचालित उपकरणों द्वारा पता लगाया जा सकता है।

अधिक जानकारी के लिए, कृपया http://all-about-java-and-weblogic-server.blogspot.in/2014/01/what-is-memory-leak-in-java.html देखें

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