C ++ कोड / प्रोजेक्ट में मेमोरी लीक कैसे करें?


180

मैं विंडोज प्लेटफॉर्म पर C ++ प्रोग्रामर हूं। मैं विजुअल स्टूडियो 2008 का उपयोग कर रहा हूं।

मैं आमतौर पर मेमोरी लीक के साथ कोड में समाप्त होता हूं।

आम तौर पर मुझे कोड का निरीक्षण करके मेमोरी लीक का पता चलता है, लेकिन यह बोझिल है और हमेशा एक अच्छा तरीका नहीं है।

चूँकि मैं एक सशुल्क मेमोरी लीक डिटेक्शन टूल का खर्च नहीं उठा सकता, इसलिए मैं चाहता था कि आप लोग मेमोरी लीक से बचने के सर्वोत्तम तरीके सुझाएं।

  1. मैं जानना चाहता हूं कि प्रोग्रामर मेमोरी लीक कैसे पा सकता है।
  2. क्या कोई मानक या प्रक्रिया है जिसे यह सुनिश्चित करने के लिए पालन करना चाहिए कि कार्यक्रम में कोई स्मृति रिसाव नहीं है?

29
"मैं आमतौर पर मेमोरी लीक के साथ कोड में समाप्त होता हूं।" यदि आप स्वचालित चर, कंटेनर और स्मार्ट पॉइंटर्स का उपयोग करते हैं (और स्मार्ट पॉइंटर्स का उपयोग करने के लिए सर्वोत्तम प्रथाओं का पालन करते हैं), तो मेमोरी लीक बेहद दुर्लभ होनी चाहिए। याद रखें, लगभग सभी मामलों में, आपको स्वचालित संसाधन प्रबंधन का उपयोग करना चाहिए
जेम्स मैकनेलिस

डुप्लिकेट मुद्दों कई सवाल, जैसे द्वारा कवर stackoverflow.com/questions/1502799/... और stackoverflow.com/questions/2820223/...
HostileFork कहते हैं न विश्वास एसई

1
@होस्टाइल फोर्क: " मेमोरी लीक के साथ कोड को आमतौर पर समाप्त करने से कैसे बचा जा सकता है " उन उत्तरों द्वारा कवर नहीं किया जाता है।
डॉक्टर ब्राउन

2
@ डॉक ब्राउन: यह भी देखने में मन नहीं लग रहा था, लेकिन यह सब कहीं और कवर किया गया है, जैसे कि stackoverflow.com/questions/45627/…
HostileFork का कहना है कि SE

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

जवाबों:


270

अनुदेश

चीजें आप की आवश्यकता होगी

  • C ++ में प्रवीणता
  • सी ++ संकलक
  • डीबगर और अन्य खोजी सॉफ्टवेयर टूल

1

ऑपरेटर मूल बातें समझें। C ++ ऑपरेटर newहीप मेमोरी को आवंटित करता है। deleteऑपरेटर मुक्त कर देते ढेर स्मृति। प्रत्येक के लिए new, आपको एक deleteऐसा उपयोग करना चाहिए कि आप उसी स्मृति को मुक्त करें जिसे आपने आवंटित किया है:

char* str = new char [30]; // Allocate 30 bytes to house a string.

delete [] str; // Clear those 30 bytes and make str point nowhere.

2

यदि आप हटा चुके हैं तो केवल मेमोरी को पुनः लोड करें नीचे दिए गए कोड में, strदूसरा आवंटन के साथ एक नया पता प्राप्त करता है। पहला पता गैर-कानूनी रूप से खो गया है, और इसलिए 30 बाइट्स हैं जो इसे इंगित करते हैं। अब उन्हें मुक्त करना असंभव है, और आपके पास मेमोरी लीक है:

char* str = new char [30]; // Give str a memory address.

// delete [] str; // Remove the first comment marking in this line to correct.

str = new char [60]; /* Give str another memory address with
                                                    the first one gone forever.*/

delete [] str; // This deletes the 60 bytes, not just the first 30.

3

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

char* str1 = new char [30];

char* str2 = new char [40];

strcpy(str1, "Memory leak");

str2 = str1; // Bad! Now the 40 bytes are impossible to free.

delete [] str2; // This deletes the 30 bytes.

delete [] str1; // Possible access violation. What a disaster!

4

स्थानीय संकेत से सावधान रहें। एक फ़ंक्शन में घोषित एक पॉइंटर को स्टैक पर आवंटित किया जाता है, लेकिन यह जिस डायनामिक चर को इंगित करता है वह ढेर पर आवंटित किया जाता है। यदि आप इसे नहीं हटाते हैं, तो यह कार्यक्रम से बाहर निकलने के बाद बनी रहेगी:

void Leak(int x){

char* p = new char [x];

// delete [] p; // Remove the first comment marking to correct.

}

5

"हटाएं" के बाद वर्ग ब्रेसिज़ पर ध्यान दें। deleteकिसी एक वस्तु को मुक्त करने के लिए स्वयं का उपयोग करें । delete []एक वर्ग सरणी को मुक्त करने के लिए चौकोर कोष्ठक के साथ प्रयोग करें । ऐसा कुछ न करें:

char* one = new char;

delete [] one; // Wrong

char* many = new char [30];

delete many; // Wrong!

6

यदि लीक अभी तक अनुमति दी गई है - मैं आमतौर पर इसे डिलर के साथ मांग रहा हूं (इसे यहां देखें: http://deleaker.com )।


3
सवाल-टिप्पणी के लिए खेद है लेकिन संकेत के बिना फ़ंक्शन मापदंडों के बारे में क्या? someFunction("some parameter")क्या मुझे फंक्शन कॉल के बाद डिलीट करना "some parameter"है someFunction, या ये अपने आप डिलीट हो जाते हैं?
19greg96

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

@ john smith plz स्पष्ट करें कि केस 3 के समान मामलों को संभालने का उचित तरीका क्या है; str2 = str1; // खराब! अब 40 बाइट्स को मुक्त करना असंभव है। कैसे 1 तो नष्ट करने के लिए ??
निहार

1
क्या होगा अगर हम char *, int, float, ... और वेक्टर, CString जैसी संरचना का उपयोग करते हैं, और किसी भी 'नए' ऑपरेटर का उपयोग बिल्कुल नहीं करते हैं, यह मेमोरी लीक का कारण नहीं होगा, क्या यह सही है?
१६३ विकीकिंग १६'१६

मैं यहाँ सिर्फ यह कह रहा हूँ कि मैंने 14 वर्षों के करीब c ++ को नहीं छुआ है ... लेकिन मुझे यह कहते हुए गर्व होता है कि मैं समझ गया था और मुझे याद है कि यह सब करने के लिए धन्यवाद c ++ पुस्तक जो अभी भी मेरे पास है और पढ़ता हूं जब मैं ' मी # के साथ ऊब गया है। वह पुस्तक स्कॉट मिशेल की प्रभावी C ++ है। ईश्वर मुझे वह पुस्तक अच्छी लगी। धन्यवाद स्कॉट!
जॉन एचएच

33

मेमोरी लीक का पता लगाने के लिए आप अपने कोड में कुछ तकनीकों का उपयोग कर सकते हैं। पता लगाने का सबसे आम और सबसे आसान तरीका है, एक मैक्रो कहना, DEBUG_NEW को परिभाषित करना और इसका उपयोग करना, साथ ही पूर्वनिर्धारित मैक्रोज़ के साथ __FILE__और __LINE__अपने कोड में मेमोरी लीक का पता लगाना। ये पूर्वनिर्धारित मैक्रोज़ आपको मेमोरी लीक की फ़ाइल और लाइन नंबर बताते हैं।

DEBUG_NEW सिर्फ एक मैक्रो है जिसे आमतौर पर इस रूप में परिभाषित किया जाता है:

#define DEBUG_NEW new(__FILE__, __LINE__)
#define new DEBUG_NEW

ताकि आप जहां भी उपयोग करें new , वह फ़ाइल और लाइन नंबर का भी पता रख सके, जिसका उपयोग आपके प्रोग्राम में मेमोरी लीक का पता लगाने के लिए किया जा सकता है।

और __FILE__, __LINE__कर रहे हैं मैक्रो पूर्वनिर्धारित जो क्रमश: फ़ाइल नाम और लाइन नंबर के रूप में मूल्यांकित जहाँ आप उन्हें का उपयोग करें!

निम्नलिखित लेख पढ़ें जो अन्य रोचक मैक्रोज़ के साथ DEBUG_NEW का उपयोग करने की तकनीक को बहुत ही खूबसूरती से बताता है:

एक क्रॉस-प्लेटफ़ॉर्म मेमोरी लीक डिटेक्टर


से Wikpedia ,

डीबग_न्यू सी ++ में एक तकनीक को ओवरलोड और / या फिर से परिभाषित करने के लिए नए और ऑपरेटर को फिर से लोड करने और मेमोरी एलोकेशन और डीललोकेशन कॉल को रोकने के लिए हटाता है, और इस प्रकार मेमोरी उपयोग के लिए एक प्रोग्राम डीबग करता है। इसमें अक्सर DEBUG_NEW नामक एक मैक्रो को परिभाषित करना शामिल है, और नए को कुछ नया जैसा बनाता है (_ FILE _, _) आवंटन पर फ़ाइल / लाइन की जानकारी रिकॉर्ड करने के LINE _) जाता है।Microsoft Visual C ++ अपने Microsoft Foundation Classes में इस तकनीक का उपयोग करता है। मैक्रो रिडिफाइनमेंट का उपयोग करने से बचने के लिए इस विधि का विस्तार करने के कुछ तरीके हैं जबकि अभी भी कुछ प्लेटफार्मों पर फ़ाइल / लाइन की जानकारी प्रदर्शित करने में सक्षम है। इस पद्धति की कई अंतर्निहित सीमाएँ हैं। यह केवल C ++ पर लागू होता है, और Malloc जैसे C फ़ंक्शन द्वारा मेमोरी लीक को पकड़ नहीं सकता है। हालांकि, यह बहुत सरल उपयोग करने के लिए और बहुत तेज हो सकता है, जब कुछ और पूर्ण मेमोरी डिबगर समाधानों की तुलना में।


4
यह #defineअतिभारित operator newऔर संकलक त्रुटियों को उत्पन्न करेगा । यहां तक ​​कि अगर आप इससे उबरने में सफल हो जाते हैं, तब भी ओवरलोड कार्यों को संबोधित नहीं किया जाएगा। हालांकि तकनीक अच्छी है, इसके लिए कभी-कभी बहुत सारे कोड परिवर्तन की आवश्यकता होती है।
इमिलिंद

1
@iammilind: निश्चित रूप से, यह तकनीक सभी समस्याओं के सभी समाधानों का इलाज नहीं है और निश्चित रूप से सभी स्थितियों में लागू नहीं है।
नवाज

@ क्रिस_vr: auto_ptrमानक कंटेनरों के साथ काम नहीं करेगा जैसे std::vector, std::listआदि। इसे देखें: stackoverflow.com/questions/111478/…
नवाज

ठीक है। FILE और लाइन का वर्णन किया गया है। क्या है operator newऔर इसके कौन से संस्करण हैं जिनका आप उपयोग कर रहे हैं?

14

कुछ प्रसिद्ध प्रोग्रामिंग तकनीकें हैं जो आपको पहली बार मेमोरी लीक होने के जोखिम को कम करने में मदद करेंगी:

  • अगर आपको अपना डायनामिक मेमोरी एलोकेशन करना है, तो लिखें newऔरdelete हमेशा हमेशा बनाएं और आवंटन / डीललोकेशन कोड को पेयरवाइज़ कहा जाता है
  • यदि आप कर सकते हैं तो गतिशील मेमोरी आवंटन से बचें। उदाहरण के लिए, vector<T> tजहाँ भी संभव हो उपयोग करेंT* t = new T[size]
  • बूस्ट स्मार्ट पॉइंटर्स ( http://www.boost.org/doc/libs/1_46_1/libs/smart_ptr/smart_ptr.htm) जैसे "स्मार्ट पॉइंटर्स" का उपयोग करें )
  • मेरा व्यक्तिगत पसंदीदा: सुनिश्चित करें कि आप एक पॉइंटर के स्वामित्व की अवधारणा को समझ गए हैं, और सुनिश्चित करें कि हर जगह जहां आप पॉइंटर्स का उपयोग करते हैं, आपको पता है कि कौन सी कोड इकाई का मालिक है
  • सीखें कि कौन से निर्माता / असाइनमेंट ऑपरेटर स्वचालित रूप से C ++ कंपाइलर द्वारा बनाए गए हैं, और इसका क्या मतलब है यदि आपके पास एक ऐसा क्लास है जो एक पॉइंटर का मालिक है (या इसका मतलब यह है कि यदि आपके पास एक क्लास है जिसमें एक ऑब्जेक्ट के लिए एक पॉइंटर होता है तो वह खुद नहीं होता है )।

मैं किसी ऑब्जेक्ट के auto_pointer का उपयोग करता हूं इसका मतलब यह है कि यह उसके अंदर अन्य सभी क्लास ऑब्जेक्ट पॉइंटर को हटा देगा।
Chris_vr

@Chris_vr: यदि आपके पास auto_pointer के बारे में कोई विशिष्ट प्रश्न है, तो मैं आपको एक उदाहरण सहित एक नया प्रश्न बनाने का सुझाव दूंगा।
डॉक्टर ब्राउन

कई पोस्ट मुझे बताती हैं कि वेक्टर <> स्पष्ट होने पर मेमोरी को मुक्त करने की गारंटी नहीं देता है। मैंने व्यक्तिगत रूप से स्वैप सामान आदि का परीक्षण किया और मैं इस निष्कर्ष पर पहुंचा कि वेक्टर <> विशेष रूप से गतिशील रूप से उपयोग किए जाने पर लीक हो रहा है। मुझे समझ में नहीं आता है कि वेक्टर <> को 'नए' और सही तरीके से क्लीनअप का उपयोग करके अपने आप को गतिशील आवंटन की सलाह दी जा सकती है। अपने एम्बेडेड कार्यक्रमों में मैं सभी लीक के कारण गतिशील सामान के लिए वेक्टर <> का उपयोग करने से बचता हूं। वहाँ मैं नए या एसटीडी का उपयोग करता हूं :: सूची
बार्ट एस

मैं वर्णों की संख्या के कारण एक दूसरी कमांड टाइप करता हूं। दुर्भाग्य से मेरे एम्बेडेड c ++ में मेरे पास एक पुराना c ++ (98?) है, जिसमें एक वेक्टर पर संकोचन_to_fit नहीं है ... हालांकि एम्बेडेड प्रोग्राम 100% पूरी तरह से दुर्घटनाग्रस्त हो जाता है जब वेक्टर का उपयोग करके मेमोरी से बाहर चला जाता है <> गतिशील रूप से
bart


8
  1. विंडोज के लिए डिबगिंग टूल डाउनलोड करें ।
  2. gflagsउपयोगकर्ता-मोड स्टैक के निशान को चालू करने के लिए उपयोगिता का उपयोग करें ।
  3. UMDHअपने कार्यक्रम की मेमोरी के कई स्नैपशॉट लेने के लिए उपयोग करें । मेमोरी आवंटित होने से पहले स्नैपशॉट लें, और एक बिंदु के बाद दूसरा स्नैपशॉट लें, जिस पर आप मानते हैं कि आपके प्रोग्राम ने मेमोरी को लीक कर दिया है। आप अपने कार्यक्रम में ठहराव या संकेत जोड़ना चाहते हैं ताकि आपको चलाने का मौका मिल सकेUMDH स्नैपशॉट और लेने का ।
  4. Daud UMDHफिर से , इस बार इसके मोड में जो दो स्नैपशॉट के बीच अंतर करता है। यह तब एक रिपोर्ट उत्पन्न करेगा जिसमें संदिग्ध मेमोरी लीक के कॉल स्टैक होते हैं।
  5. gflagsजब आप काम कर लें तो अपनी पिछली सेटिंग्स को पुनर्स्थापित करें ।

UMDHआपको CRT डिबग हीप से अधिक जानकारी देगा क्योंकि यह आपकी संपूर्ण प्रक्रिया में मेमोरी आवंटन देख रहा है; यह आपको यह भी बता सकता है कि क्या तीसरे पक्ष के घटक लीक कर रहे हैं।


1
मैं मानक प्रोफाइलर के बजाय डेल्केर और वैलग्राइंड पसंद करता हूं
z0r1fan

8

"Valgrind" चल सकता है:

1) मेमोरी लीक्स को पहचानने में मदद करें - आपको यह दिखाएं कि आपके पास कितने मेमोरी लीक हैं, और कोड में लाइनों को इंगित करें जहां लीक हुई मेमोरी आवंटित की गई थी।

2) मुक्त स्मृति (जैसे अनुचित कॉल ) के लिए गलत प्रयासों को इंगित करेंdelete ) की

"Valgrind" का उपयोग करने के लिए निर्देश

1) यहां वैलग्राइंड प्राप्त करें

2) के साथ अपना कोड संकलित करें -g ध्वज

3) अपने शेल रन में:

valgrind --leak-check=yes myprog arg1 arg2

जहां "myprog" आपका संकलित कार्यक्रम है और arg1,arg2 आपके प्रोग्राम की दलीलें।

4) परिणाम कॉल की एक सूची है malloc/ newजिसके पास बाद में कॉल को हटाने के लिए नहीं था।

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

==4230==    at 0x1B977DD0: malloc (vg_replace_malloc.c:136)

==4230==    by 0x804990F: main (example.c:6)

आपको बताता है कि किस लाइन में malloc(जिसे मुक्त नहीं किया गया था) कहा जाता था।

जैसा कि दूसरों द्वारा बताया गया है, सुनिश्चित करें कि प्रत्येक new/ mallocकॉल के लिए, आपके पास एक बाद delete/ freeकॉल है।


6

यदि आप gcc का उपयोग करते हैं, तो उपलब्ध gprof है।

मैं यह जानना चाहता था कि प्रोग्रामर मेमोरी लीक कैसे ढूंढता है

कुछ उपकरण का उपयोग करते हैं, कुछ आप जो करते हैं, वह सहकर्मी कोड समीक्षा के माध्यम से भी कर सकता है

क्या कोई मानक या प्रक्रिया है, जिसे यह सुनिश्चित करने के लिए पालन करना चाहिए कि कार्यक्रम में कोई स्मृति रिसाव नहीं है

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


कुछ समय हम कंस्ट्रक्टर में आवंटित को नष्ट नहीं कर सकते। उस अवसर पर क्या करें।
Chris_vr

5
  1. दृश्य स्टूडियो में, स्मृति रिसाव के लिए एक डिटेक्टर बनाया गया है जिसे सी रनटाइम लाइब्रेरी कहा जाता है। जब आपका प्रोग्राम मुख्य फ़ंक्शन के वापस आने के बाद बाहर निकलता है, तो CRT आपके एप्लिकेशन के डीबग ढेर की जाँच करेगा। यदि आपके पास डिबग हीप पर अभी भी कोई ब्लॉक आवंटित है, तो आपके पास मेमोरी लीक है।

  2. यह मंच C / C ++ में मेमोरी लीकेज से बचने के कुछ तरीकों पर चर्चा करता है।


5

की घटनाओं के लिए अपने कोड को खोजें new, और सुनिश्चित करें कि वे सभी एक विध्वंसक के साथ एक विध्वंसक में एक मिलान हटाने के साथ होते हैं। सुनिश्चित करें कि यह उस निर्माता में संभवतः एकमात्र फेंकने वाला ऑपरेशन है। ऐसा करने का एक सरल तरीका यह है कि आप सभी बिंदुओं को लपेटें std::auto_ptr, या boost::scoped_ptr(यह निर्भर करता है कि आपको स्थानांतरित शब्दार्थ की आवश्यकता है या नहीं)। भविष्य के सभी कोड के लिए बस यह सुनिश्चित करें कि प्रत्येक संसाधन किसी ऐसी वस्तु के स्वामित्व में है जो संसाधन को उसके विध्वंसक में साफ करता है। यदि आपको स्थानांतरित शब्दार्थ की आवश्यकता है तो आप एक कंपाइलर में अपग्रेड कर सकते हैं जो r-value reference (VS2010 मुझे विश्वास है) का समर्थन करता है और मूव कन्स्ट्रक्टर बनाते हैं। यदि आप ऐसा नहीं करना चाहते हैं, तो आप विभिन्न प्रकार की ट्रिकी तकनीकों का उपयोग कर सकते हैं, जिसमें स्वैप का कर्तव्यनिष्ठ उपयोग शामिल है, या Boost.Move पुस्तकालय का प्रयास करें।


कंस्ट्रक्टर में आवंटित मेमोरी को हटाना हमेशा संभव नहीं होता है। इस स्थिति से निपटने के लिए कैसे
Chris_vr

@Chris_vr तुम्हारा क्या मतलब है? यदि आपके सभी पॉइंटर सदस्य हैं scope_ptr, और प्रत्येक को व्यक्तिगत रूप से प्रारंभ किया गया है, तो सफलतापूर्वक बनाए गए सभी अपने पॉइंटर्स को हटा देंगे, और अन्य अभी भी वैसे भी आवंटित मेमोरी में पॉइंटर्स नहीं रखेंगे। मैं काम से घर पहुंचने पर कुछ घंटों में एक उदाहरण रखूंगा।
मकारसे

@Chris_vr: यदि आपके पास एक विशिष्ट उदाहरण है, तो इसे एक नए प्रश्न के रूप में पोस्ट करें, इसलिए हम वहां इस पर चर्चा कर सकते हैं।
डॉक ब्राउन

5

मेमोरी लीक का पता लगाने के लिए आप टूल Valgrind का उपयोग कर सकते हैं।

इसके अलावा, किसी विशेष फ़ंक्शन में रिसाव को खोजने के लिए, फ़ंक्शन के अंत में निकास (0) का उपयोग करें और फिर इसे Valgrind के साथ चलाएं

`$` valgrind ./your_CPP_program 

5

स्वचालित मेमोरी लीक चेकर्स का एक सर्वेक्षण

इस उत्तर में, मैं मेमोरी लीक उदाहरण को समझने के लिए एक सरल आसान में कई अलग-अलग मेमोरी लीक चेकर्स की तुलना करता हूं।

कुछ भी करने से पहले, आसन विकी में इस विशाल तालिका को देखें, जो मनुष्य को ज्ञात सभी साधनों की तुलना करती है: https://github.com/google/sanitizers/wiki/AddressSanitizerComparisonOfMemoryTools/d06220f759fec97066888e5f27c7e722832b09b0924

उदाहरण का विश्लेषण किया जाएगा:

main.c

#include <stdlib.h>

void * my_malloc(size_t n) {
    return malloc(n);
}

void leaky(size_t n, int do_leak) {
    void *p = my_malloc(n);
    if (!do_leak) {
        free(p);
    }
}

int main(void) {
    leaky(0x10, 0);
    leaky(0x10, 1);
    leaky(0x100, 0);
    leaky(0x100, 1);
    leaky(0x1000, 0);
    leaky(0x1000, 1);
}

गिटहब अपस्ट्रीम

हम यह देखने की कोशिश करेंगे कि विभिन्न उपकरण स्पष्ट रूप से हमें टपकी कॉल के लिए कैसे इंगित करते हैं।

Google द्वारा gperftools से tcmalloc

https://github.com/gperftools/gperftools

उबंटू 19.04 पर उपयोग:

sudo apt-get install google-perftools
gcc -ggdb3 -o main.out main.c -ltcmalloc
PPROF_PATH=/usr/bin/google-pprof \
  HEAPCHECK=normal \
  HEAPPROFILE=ble \
  ./main.out \
;
google-pprof main.out ble.0001.heap --text

प्रोग्राम रन के आउटपुट में मेमोरी रिसाव विश्लेषण होता है:

WARNING: Perftools heap leak checker is active -- Performance may suffer
Starting tracking the heap
Dumping heap profile to ble.0001.heap (Exiting, 4 kB in use)
Have memory regions w/o callers: might report false leaks
Leak check _main_ detected leaks of 272 bytes in 2 objects
The 2 largest leaks:
Using local file ./main.out.
Leak of 256 bytes in 1 objects allocated from:
        @ 555bf6e5815d my_malloc
        @ 555bf6e5817a leaky
        @ 555bf6e581d3 main
        @ 7f71e88c9b6b __libc_start_main
        @ 555bf6e5808a _start
Leak of 16 bytes in 1 objects allocated from:
        @ 555bf6e5815d my_malloc
        @ 555bf6e5817a leaky
        @ 555bf6e581b5 main
        @ 7f71e88c9b6b __libc_start_main
        @ 555bf6e5808a _start


If the preceding stack traces are not enough to find the leaks, try running THIS shell command:

pprof ./main.out "/tmp/main.out.24744._main_-end.heap" --inuse_objects --lines --heapcheck  --edgefraction=1e-10 --nodefraction=1e-10 --gv

If you are still puzzled about why the leaks are there, try rerunning this program with HEAP_CHECK_TEST_POINTER_ALIGNMENT=1 and/or with HEAP_CHECK_MAX_POINTER_OFFSET=-1
If the leak report occurs in a small fraction of runs, try running with TCMALLOC_MAX_FREE_QUEUE_SIZE of few hundred MB or with TCMALLOC_RECLAIM_MEMORY=false, it might help find leaks more re
Exiting with error code (instead of crashing) because of whole-program memory leaks

और उत्पादन google-pprofमें ढेर उपयोग विश्लेषण शामिल हैं:

Using local file main.out.
Using local file ble.0001.heap.
Total: 0.0 MB
     0.0 100.0% 100.0%      0.0 100.0% my_malloc
     0.0   0.0% 100.0%      0.0 100.0% __libc_start_main
     0.0   0.0% 100.0%      0.0 100.0% _start
     0.0   0.0% 100.0%      0.0 100.0% leaky
     0.0   0.0% 100.0%      0.0 100.0% main

आउटपुट हमें दो तीन लीक की ओर इशारा करता है:

Leak of 256 bytes in 1 objects allocated from:
        @ 555bf6e5815d my_malloc
        @ 555bf6e5817a leaky
        @ 555bf6e581d3 main
        @ 7f71e88c9b6b __libc_start_main
        @ 555bf6e5808a _start
Leak of 16 bytes in 1 objects allocated from:
        @ 555bf6e5815d my_malloc
        @ 555bf6e5817a leaky
        @ 555bf6e581b5 main
        @ 7f71e88c9b6b __libc_start_main
        @ 555bf6e5808a _start

मुझे यकीन नहीं है कि तीसरा क्यों नहीं दिखा

किसी भी मामले में, जब आमतौर पर जब कुछ लीक होता है, तो यह बहुत बार होता है, और जब मैंने इसे एक वास्तविक परियोजना पर इस्तेमाल किया, तो मैंने बस लीक होने वाले फ़ंक्शन को बहुत आसानी से इंगित किया।

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

आगे के प्रलेखन:

इसे भी देखें: TCMalloc का उपयोग कैसे करें?

उबंटू 19.04 में परीक्षण किया गया, google-perftools 2.5-2।

एड्रेस सेनिटाइज़र (आसन) भी Google द्वारा

https://github.com/google/sanitizers

पहले उल्लेख किया गया था: C ++ कोड / प्रोजेक्ट में मेमोरी लीक कैसे करें?TODO बनाम tcmalloc।

यह पहले से ही जीसीसी में एकीकृत है, इसलिए आप बस कर सकते हैं:

gcc -fsanitize=address -ggdb3 -o main.out main.c
./main.out 

और निष्पादन आउटपुट:

=================================================================
==27223==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 4096 byte(s) in 1 object(s) allocated from:
    #0 0x7fabbefc5448 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x10c448)
    #1 0x55bf86c5f17c in my_malloc /home/ciro/test/main.c:4
    #2 0x55bf86c5f199 in leaky /home/ciro/test/main.c:8
    #3 0x55bf86c5f210 in main /home/ciro/test/main.c:20
    #4 0x7fabbecf4b6a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x26b6a)

Direct leak of 256 byte(s) in 1 object(s) allocated from:
    #0 0x7fabbefc5448 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x10c448)
    #1 0x55bf86c5f17c in my_malloc /home/ciro/test/main.c:4
    #2 0x55bf86c5f199 in leaky /home/ciro/test/main.c:8
    #3 0x55bf86c5f1f2 in main /home/ciro/test/main.c:18
    #4 0x7fabbecf4b6a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x26b6a)

Direct leak of 16 byte(s) in 1 object(s) allocated from:
    #0 0x7fabbefc5448 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x10c448)
    #1 0x55bf86c5f17c in my_malloc /home/ciro/test/main.c:4
    #2 0x55bf86c5f199 in leaky /home/ciro/test/main.c:8
    #3 0x55bf86c5f1d4 in main /home/ciro/test/main.c:16
    #4 0x7fabbecf4b6a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x26b6a)

SUMMARY: AddressSanitizer: 4368 byte(s) leaked in 3 allocation(s).

जो स्पष्ट रूप से सभी लीक की पहचान करता है। अच्छा!

आसन अन्य शांत जांच भी कर सकते हैं जैसे कि बाहर की सीमाएं लिखती हैं: स्टैक स्मैशिंग का पता चला

उबंटू 19.04, जीसीसी 8.3.0 में परीक्षण किया गया।

वेलग्रिंड

http://www.valgrind.org/

पहले बताया गया: https://stackoverflow.com/a/37661630/895245

उपयोग:

sudo apt-get install valgrind
gcc -ggdb3 -o main.out main.c
valgrind --leak-check=yes ./main.out

आउटपुट:

==32178== Memcheck, a memory error detector
==32178== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==32178== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==32178== Command: ./main.out
==32178== 
==32178== 
==32178== HEAP SUMMARY:
==32178==     in use at exit: 4,368 bytes in 3 blocks
==32178==   total heap usage: 6 allocs, 3 frees, 8,736 bytes allocated
==32178== 
==32178== 16 bytes in 1 blocks are definitely lost in loss record 1 of 3
==32178==    at 0x483874F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==32178==    by 0x10915C: my_malloc (main.c:4)
==32178==    by 0x109179: leaky (main.c:8)
==32178==    by 0x1091B4: main (main.c:16)
==32178== 
==32178== 256 bytes in 1 blocks are definitely lost in loss record 2 of 3
==32178==    at 0x483874F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==32178==    by 0x10915C: my_malloc (main.c:4)
==32178==    by 0x109179: leaky (main.c:8)
==32178==    by 0x1091D2: main (main.c:18)
==32178== 
==32178== 4,096 bytes in 1 blocks are definitely lost in loss record 3 of 3
==32178==    at 0x483874F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==32178==    by 0x10915C: my_malloc (main.c:4)
==32178==    by 0x109179: leaky (main.c:8)
==32178==    by 0x1091F0: main (main.c:20)
==32178== 
==32178== LEAK SUMMARY:
==32178==    definitely lost: 4,368 bytes in 3 blocks
==32178==    indirectly lost: 0 bytes in 0 blocks
==32178==      possibly lost: 0 bytes in 0 blocks
==32178==    still reachable: 0 bytes in 0 blocks
==32178==         suppressed: 0 bytes in 0 blocks
==32178== 
==32178== For counts of detected and suppressed errors, rerun with: -v
==32178== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)

तो एक बार फिर, सभी लीक का पता चला था।

यह भी देखें: मैं मेमोरी लीक को खोजने के लिए वेलग्रिंड का उपयोग कैसे करूं?

उबंटू 19.04 में परीक्षण किया गया, 3.14.0 मान्य।


4

विजुअल लीक डिटेक्टर (VLD) विजुअल C ++ के लिए एक स्वतंत्र, मजबूत, ओपन-सोर्स मेमोरी लीक डिटेक्शन सिस्टम है।

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

यदि आपके पास केवल क्रैश डंप है, तो आप विंडबग !heap -lकमांड का उपयोग कर सकते हैं , यह लीक हुए हीप ब्लॉकों का पता लगाएगा। बेहतर है कि gflags विकल्प खोलें: "उपयोगकर्ता मोड स्टैक ट्रेस डेटाबेस बनाएँ", फिर आपको मेमोरी आवंटन कॉल स्टैक दिखाई देगा।


4

MTuner MSVC, GCC और Clang कंपाइलर्स को सपोर्ट करने वाला एक फ्री मल्टी प्लेटफॉर्म मेमोरी प्रोफाइलिंग, लीक डिटेक्शन एंड एनालिसिस टूल है। विशेषताओं में शामिल:

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

उपयोगकर्ता किसी भी सॉफ़्टवेयर लक्ष्यीकरण प्लेटफ़ॉर्म को GCC या Clang क्रॉस कंपाइलर के साथ प्रोफाइल कर सकते हैं। MTuner विंडोज, PlayStation 4 और PlayStation 3 प्लेटफार्मों के समर्थन में बनाया गया है।


यह स्वीकृत उत्तर होना चाहिए। यह एक महान उपकरण है और अन्य लोगों को नहीं दे सकने वाले आवंटन / सौदे की मात्रा को संभाल सकता है।
सर्ग रोजैच

3

विंडोज पर आप CRT डिबग हीप का उपयोग कर सकते हैं ।

क्या कोई मानक या प्रक्रिया है, जिसे यह सुनिश्चित करने के लिए पालन करना चाहिए कि कार्यक्रम में कोई स्मृति रिसाव नहीं है।

हाँ, मैन्युअल मेमोरी प्रबंधन का उपयोग न करें (यदि आप कभी भी फोन करते हैं deleteया delete[]मैन्युअल करते हैं, तो आप इसे गलत कर रहे हैं)। RAII और स्मार्ट पॉइंटर्स का उपयोग करें, निरपेक्ष न्यूनतम तक ढेर आवंटन को सीमित करें (अधिकांश समय, स्वचालित चर पर्याप्त होगा)।


3

अपने प्रश्न के दूसरे भाग का उत्तर देते हुए,

क्या कोई मानक या प्रक्रिया है, जिसे यह सुनिश्चित करने के लिए पालन करना चाहिए कि कार्यक्रम में कोई स्मृति रिसाव नहीं है।

हाँ वहाँ है। और यह C और C ++ के बीच के प्रमुख अंतरों में से एक है।

C ++ में, आपको कभी भी newया deleteअपने उपयोगकर्ता कोड में कॉल नहीं करना चाहिए । RAII एक बहुत ही आमतौर पर इस्तेमाल की जाने वाली तकनीक है, जो संसाधन प्रबंधन की समस्या को बहुत हल करती है। आपके प्रोग्राम में प्रत्येक संसाधन (एक संसाधन कुछ भी है जिसे अधिग्रहित किया जाना है, और फिर बाद में जारी किया गया है: फ़ाइल हैंडल, नेटवर्क सॉकेट, डेटाबेस कनेक्शन, लेकिन यह भी सादे मेमोरी आवंटन, और कुछ मामलों में, एपीआई कॉल की जोड़ी (शुरुआती) ) / एंडएक्स (), लॉकवाई (), अनलॉकी ()) को एक कक्षा में लपेटा जाना चाहिए, जहां:

  • कंस्ट्रक्टर संसाधन को बुलाकर प्राप्त करता हैnew यदि संसाधन मेमोरो आवंटन है तो )
  • विध्वंसक संसाधन जारी करता है,
  • नकल और असाइनमेंट को या तो रोका जाता है (कॉपी कंस्ट्रक्टर और असाइनमेंट ऑपरेटरों को निजी बनाकर), या सही तरीके से काम करने के लिए लागू किया जाता है (उदाहरण के लिए अंतर्निहित संसाधन को क्लोन करके)

यह वर्ग तो स्थानीय स्तर पर एक वर्ग के सदस्य के रूप में, और instantiated है, ढेर पर, या नहीं पर कॉल करके newऔर एक सूचक भंडारण।

आपको अक्सर इन वर्गों को स्वयं परिभाषित करने की आवश्यकता नहीं है। मानक पुस्तकालय कंटेनर इस तरह से व्यवहार करते हैं, ताकि std::vectorवेक्टर नष्ट हो जाने पर किसी भी वस्तु को संग्रहित किया जा सके। इसलिए फिर से, एक पॉइंटर को कंटेनर में न रखें (जिसमें आपको कॉल करने की आवश्यकता होगी ) newऔर delete, बल्कि ऑब्जेक्ट खुद (जो आपको मुफ्त में मेमोरी मैनेजमेंट देता है )। इसी तरह, स्मार्ट पॉइंटर क्लासेस का उपयोग उन वस्तुओं को आसानी से लपेटने के लिए किया जा सकता है, जिन्हें अभी आवंटित किया जाना हैnew उनके , और उनके जीवनकाल को नियंत्रित करना है।

इसका मतलब यह है कि जब ऑब्जेक्ट दायरे से बाहर हो जाता है, तो यह स्वचालित रूप से नष्ट हो जाता है, और इसके संसाधन जारी और साफ हो जाते हैं।

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


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

@ क्रिस: यह मानते हुए कि स्मार्ट पॉइंटर द्वारा इंगित की जाने वाली वस्तु में एक विध्वंसक होता है जो आवश्यक सफाई करता है या वस्तु में ऐसे सदस्य होते हैं जो स्वयं आवश्यक सफाई करने के लिए विध्वंसक होते हैं। संक्षेप में, जब तक प्रत्येक वस्तु स्वयं का ख्याल रखती है (तब तक नष्ट होने के बाद खुद को साफ करना), और जब तक प्रत्येक वस्तु को मूल्य द्वारा संग्रहीत किया जाता है, न कि सूचक के रूप में, तब तक हर चीज जिसे मुक्त करने की आवश्यकता होती है, वह मुक्त हो जाएगी
जुलफ j

3

AddressSanitizer (आसन) एक तेजी से स्मृति त्रुटि डिटेक्टर है। यह C / C ++ प्रोग्राम में उपयोग के बाद-मुक्त और {ढेर, स्टैक, ग्लोबल} -Buffer ओवरफ्लो बग्स पाता है। यह पाता है:

  • मुफ्त के बाद उपयोग करें (डैन्गलिंग पॉइंटर डिफरेंस)
  • ढेर बफर अतिप्रवाह
  • ढेर बफर अतिप्रवाह
  • वैश्विक बफर अतिप्रवाह
  • वापसी के बाद उपयोग करें
  • प्रारंभिक आदेश कीड़े

यह उपकरण बहुत तेज है। साधन कार्यक्रम का औसत मंदी ~ 2x है।



0

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


-1

सुनिश्चित करें कि सभी ढेर मेमोरी सफलतापूर्वक मुक्त हो गई है। यदि आप कभी भी ढेर पर मेमोरी आवंटित नहीं करते हैं तो कोई ज़रूरत नहीं है। यदि आप ऐसा करते हैं, तो आप जितनी बार मैलोक मेमोरी को याद करते हैं, उतने समय की गिनती करें और जितनी बार आप फ्री मैमोरी करें, उतनी बार गिनती करें।


-3

आवेदन कोड में न तो "नया" या "हटाएं" का उपयोग किया जाना चाहिए। इसके बजाय, एक नया प्रकार बनाएं जो प्रबंधक / कार्यकर्ता मुहावरे का उपयोग करता है, जिसमें प्रबंधक वर्ग स्मृति आवंटित करता है और कार्यकर्ता ऑब्जेक्ट को अन्य सभी कार्यों को अग्रेषित करता है।

दुर्भाग्य से यह अधिक काम की तुलना में यह होना चाहिए क्योंकि C ++ में "ऑपरेटर" का अधिभार नहीं है। यह बहुरूपता की उपस्थिति में और भी अधिक काम है।

लेकिन यह प्रयास के लायक है क्योंकि आपको तब मेमोरी लीक के बारे में चिंता करने की ज़रूरत नहीं है, जिसका अर्थ है कि आपको उनके लिए भी नहीं देखना है।

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