2012-01-27 9 views
45

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

#include<iostream> 
#include<cstdlib> 
using namespace std; 
int main() 
{ 
     std::string myname("Is there any leaks"); 
     exit(0); 
} 

और इस पर चल valgrind मुझे मिल गया:

==20943== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 26 from 1) 
==20943== malloc/free: in use at exit: 360,645 bytes in 12,854 blocks. 
==20943== malloc/free: 65,451 allocs, 52,597 frees, 2,186,968 bytes allocated. 
==20943== For counts of detected errors, rerun with: -v 
==20943== searching for pointers to 12,854 not-freed blocks. 
==20943== checked 424,628 bytes. 
==20943== 
==20943== LEAK SUMMARY: 
==20943== definitely lost: 0 bytes in 0 blocks. 
==20943==  possibly lost: 917 bytes in 6 blocks. 
==20943== still reachable: 359,728 bytes in 12,848 blocks. 
==20943==   suppressed: 0 bytes in 0 blocks. 
==20943== Reachable blocks (those to which a pointer was found) are not shown. 
==20943== To see them, rerun with: --show-reachable=yes 

तो यह मुझे मारा है कि हम जबरदस्ती बाहर आ गए हैं (जो मैं प्रदर्शन किया मेरे मूल सी ++ कोड में भी)। अब समस्या यह है कि मैं प्रोग्राम से बाहर निकलना चाहता हूं क्योंकि मेरा पिछला पुराना कोड नए कोड की निकास स्थिति के लिए इंतजार कर रहा है। उदाहरण के लिए binary a.out b.out की निकास स्थिति के लिए प्रतीक्षा करता है। मेमोरी लीक से बचने का कोई तरीका है, या मुझे वास्तव में मेमोरी लीक के बारे में चिंता करनी चाहिए क्योंकि कार्यक्रम उस बिंदु पर पहले ही बाहर निकल रहा है।

यह मेरे लिए एक और सवाल उठाता है, क्या ऐसा कोड हानिकारक है?

#include<stdio.h> 
#include<cstdlib> 
int main() 
{ 
     char *p=(char *)malloc(sizeof(char)*1000); 
     exit(0); 
} 
+55

मुख्य() से मूल्य लौटने से आपकी प्रक्रिया के निकास कोड के रूप में उस मान का उपयोग किया जाएगा। – tinman

+2

ध्यान दें कि, जैसा कि वाल्ग्रिंड सही ढंग से इंगित करता है, आपके पास इस मामले में कोई लीक संसाधन नहीं है। प्रक्रिया समय के अंत में आवंटित स्मृति के कुछ बाइट्स अभी भी पहुंच योग्य हैं (जिनके पास अभी भी एक सूचक है), लेकिन यह "रिसाव" नहीं है। –

+10

जैसा कि आपने अब तक कोई संदेह नहीं पढ़ा है, "निकास निकालें;" "निकास (निकास कोड) से काफी बेहतर है;" क्योंकि, कार्यक्षमता वे दोनों निकास कोड स्थिति सेट करते हैं। "वापसी" सफाई का एक बेहतर काम करता है, जबकि, "निकास" सफाई को रोकने की संभावना है। –

उत्तर

63

आप exit() का उपयोग करने पर जोर देते हैं हैं:

#include<iostream> 
int main(){ 
    { 
     std::string myname("Are there any leaks?"); 
    } 
    exit(0); 
} 

इसके अलावा, जब आप main से लौटने दिए गए मान आवेदन के बाहर निकलने के कोड हो जाता है। इसलिए यदि आप बाहर निकलने के कोड को पास करना चाहते हैं, तो return exitCode;exit के बजाय return exitCode; का उपयोग करें।

उस भाग के बारे में:

यह भी मेरे लिए एक और सवाल उठाना, इस तरह के एक कोड हानिकारक है?

हां, क्योंकि यह बीएडी प्रोग्रामिंग आदत है।

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

हालांकि, स्लोपी/लीकी कोड लिखना आदत में बदल सकता है, इसलिए आपकी गड़बड़ी को साफ करने के लिए ओएस पर भरोसा करना एक बुरा विचार है।

+14

ओएस ** शायद स्मृति को साफ कर सकता है, ऐसा करने की वास्तव में गारंटी नहीं है (हालांकि आमतौर पर यह होगा)। – TC1

+4

केवल एक खराब ओएस ऐसा नहीं करेगा। संहिता आमतौर पर खराब होती है, जब तक कि अन्यथा साबित न हो जाए। – whitequark

+72

प्रो-टिप: मान लीजिए कि आप डेथ स्टेशन 9000 पर चल रहे हैं, एक मशीन जिसका प्राथमिक ऑपरेटिंग सिस्टम बिल्ली के बच्चे के दिमाग से स्मृति आवंटित करता है, और अगर इसे स्पष्ट रूप से करने के लिए कहा जाता है तो उसे वापस रखता है। इसके अलावा, अपरिभाषित व्यवहार के किसी भी उदाहरण के परिणामस्वरूप पृथ्वी का विनाश होगा। –

22

यह भी मेरे लिए एक और सवाल उठाना, इस तरह के एक कोड हानिकारक है?

#include<stdio.h> 
int main() 
{ 
     char *p=(char *)malloc(sizeof(char)*1000); 
     exit(0); 
} 

यह आधुनिक ऑपरेटिंग सिस्टम पर हानिकारक नहीं है, क्योंकि वे जब प्रक्रिया समाप्त हो जाती है स्वचालित रूप से एक प्रक्रिया के स्वामित्व वाले सभी संसाधनों बंद हो जाएगा।

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

+27

लेकिन यह आपके रखरखाव करने वालों के लिए हानिकारक हो सकता है कोड, वैध समस्याओं को ट्रैक करने के लिए वाल्ग्रिंड जैसे टूल का उपयोग करने में कठिन समय होगा। –

+1

@ जॉनजविनक: हाँ! – sbi

+0

@JohnZwinck शायद यह तर्क है कि ऐसे उपकरणों को क्यों सुधारना चाहिए।मेरा मतलब है कि वे वर्तमान में एक वैध तकनीक को रोक रहे हैं: ऐसा कुछ करने के लिए समय नहीं बिताएं जो ओएस बहुत बेहतर कर सके। –

0

यदि प्रोग्राम बाहर निकल रहा है, तो आपको malloc या new के साथ आवंटित स्मृति के बारे में चिंता करने की आवश्यकता नहीं है। ओएस इसका ख्याल रखेगा - आपकी प्रक्रिया में कुछ भी 'आभासी पता स्थान विशेष रूप से प्रक्रिया समाप्त होने पर दूर हो जाएगा। यदि आप साझा मेमोरी या नामित पाइप का उपयोग कर रहे हैं तो यह अभी भी चिंता का विषय हो सकता है।

+3

फिर भी, यह ध्यान में रखा जाना चाहिए कि 'निकास' स्टैक पर आवंटित वस्तुओं के लिए विनाशकों को कॉल नहीं करता है (इसलिए उदा। फ़ाइल बफर फ़्लश नहीं किए जा सकते हैं), इसलिए आपको शायद इसे किसी भी तरह से टालना चाहिए। –

65

main के अंत में exit(0); के बजाय return 0; का उपयोग करें। exit का उपयोग विनाशकों के निष्पादन को रोकता है।

+0

जैसा कि मैंने बताया है मुझे बाहर निकलने का उपयोग करना है क्योंकि एक और प्रोग्राम है जो इस कोड की निकास स्थिति की प्रतीक्षा कर रहा है। चूंकि प्रोग्राम a.out कुछ ऐसा करने के लिए मजबूर हो रहा है जैसे सी ++ कोड को कॉल करना, जब आपकी पूरी परियोजना सी में है –

+38

उदाहरण के लिए रिटर्न 12 का उपयोग करना ऑपरेटिंग सिस्टम को बाहर निकलने के लिए उसी निकास स्थिति को वापस कर देना चाहिए (12) इसे छोड़कर इसे साफ़ करें । – jcoder

+10

बस इसे स्पष्ट करने के लिए, @Piyush - * नहीं, आपको बाहर निकलने की आवश्यकता नहीं है *। जैसा कि जॉनबी कहते हैं, मुख्य से लौटाया गया पूर्णांक निकास स्थिति के रूप में उपयोग किया जाता है - यही वह है जो इसके लिए है। – Useless

1

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

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

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

4

मेमोरी रिसाव से बचने के लिए, exit पर कॉल करने के बजाय main से स्थिति लौटाएं। यदि आप शून्य लौट रहे हैं, तो आप चाहें तो return कथन छोड़ सकते हैं; कार्यक्रम उस मामले में शून्य की स्थिति से बाहर निकल जाएगा।

यह मेरे लिए एक और सवाल उठाता है, क्या ऐसा कोड हानिकारक है?

एक आधुनिक ऑपरेटिंग सिस्टम पर, इससे कोई नुकसान नहीं होगा - कार्यक्रम समाप्त होने पर सभी संसाधन स्वचालित रूप से पुनः प्राप्त किए जाते हैं। हालांकि, यह वास्तविक समस्याओं को खोजने के लिए वालग्रिंड जैसे टूल का उपयोग करना कठिन बनाता है, इसलिए यदि आप कर सकते हैं तो हानिरहित स्मृति लीक से बचने के लिए सबसे अच्छा है।

1

यदि आप निष्पादन तोड़ना चाहते हैं और विनाशकों को पार किए बिना वापसी कोड पास करना चाहते हैं, अपवाद फेंक दें, और main() में अपवाद से वापसी मूल्य निकालें।

+0

'std :: exit()' को कॉल करने के बजाय आप ऐसा क्यों करना चाहते हैं? और उस रखरखाव प्रोग्रामर के बारे में क्या, जो अब से 'कैच (...)' तीन साल में रखेगा, क्योंकि उसने नहीं सोचा था कि उसके 13 अपवाद प्रकार (जिसे वह व्यवस्थित करने के लिए आलसी है) के अलावा कुछ भी आ सकता है उस सबमिशन से बाहर? – sbi

2
#include<iostream> 
using namespace std; 
int main() 
{ 
    { 
     std::string myname("Is there any leaks"); 
    } 
    exit(0); 
} 
0

एक अलग राय जोड़ने के लिए।

इस तरह का कोड हानिकारक टोपी नहीं है। जब प्रक्रिया समाप्त हो जाती है तो ओएस सबकुछ की देखभाल करेगा। बाकी सब कुछ एक अस्थिर ओएस में परिणाम। बस सुनिश्चित करें कि आपका लगातार डेटा (फाइलें, ...) सुसंगत है।

कुछ और आगे बढ़ने के लिए, स्पष्ट रूप से प्रोग्राम निकास पर स्मृति मुक्त करने से हानिकारक हो सकता है।

  1. कार्यक्रम बाहर निकलने के समय लेता है (क्या तुमने कभी एक कार्यक्रम के लिए प्रतीक्षा करने तक कंप्यूटर बंद हो जाता बाहर निकलने के लिए परेशान हो जाते है?)
  2. विनाश के सही क्रम हमेशा तुच्छ, विशेष रूप से 3 पार्टी घटकों के साथ (मैं है कुछ कार्यक्रमों संभावना है कि बाहर निकलने पर दुर्घटना)
  3. The OS may not let you free memorymain (* छोड़ने के बाद) याद है और अपने कार्यक्रम को मारने के बजाय

वेलग्रिंड आप एक विशिष्ट उत्पादन दे तो आप इस बस बनाने के लिए जोखिम है?(**)


(*)

#include<iostream> 
using namespace std; 
std::string myname("Is there any leaks"); 
int main() { 
     exit(0); 
} 

(**) ठीक है, निश्चित रूप से किसी भी स्मृति विश्लेषक के उत्पादन में 'शोर' के बिना अधिक उपयोगी है। डिबग मोड में बाहर निकलने पर स्पष्ट रूप से स्मृति को खाली करने के बारे में क्या?

5

ज्यादातर मामलों में, अपने आप को साफ करने के लायक है, पहले से दिए गए कई अच्छे कारणों से: बेहतर रखरखाव, उपकरणों की जांच से बेहतर उपयोगिता आदि।

यदि साफ करने के अन्य कार्यात्मक कारण हैं, तो शायद आपका डेटा एक सतत स्टोर में सहेजा गया है, तो आपके पास कोई विकल्प नहीं है - आपको साफ करना होगा (हालांकि आप अपने डिज़ाइन पर पुनर्विचार करना चाहेंगे)।

हालांकि कुछ मामलों में, बाहर निकलना और "रिसाव" करना बेहतर हो सकता है।

किसी प्रोग्राम के अंत में, आपकी प्रक्रिया से बाहर निकलने जा रहा है। जब ऐसा होता है, तो ऑपरेटिंग सिस्टम आपके प्रोग्राम द्वारा आवंटित किसी भी स्मृति को पुनर्प्राप्त करेगा और कुछ मामलों में यह इसे और अधिक तेज़ी से कर सकता है।

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

आप ऐसी संरचना के माध्यम से चलाने के लिए लाखों मेमोरी ऑपरेशंस कर सकते हैं।

उपयोगकर्ता आपके प्रोग्राम से बाहर निकलना चाहता है, और वे वहां 10 सेकंड के लिए बैठते हैं जो जंक प्रसंस्करण के समूह की प्रतीक्षा करते हैं। वे परिणाम में रुचि नहीं ले सकते हैं - वे कार्यक्रम छोड़ने के बाद सभी को छोड़ रहे हैं।

यदि आप इसे "रिसाव" देते हैं, तो ऑपरेटिंग सिस्टम आपकी प्रक्रिया को आवंटित स्मृति के पूरे ब्लॉक को और अधिक तेज़ी से पुनः प्राप्त कर सकता है। यह संरचनाओं और किसी ऑब्जेक्ट क्लीनअप की परवाह नहीं करता है।

http://blogs.msdn.com/b/oldnewthing/archive/2012/01/05/10253268.aspx

अंततः आपको समझना चाहिए कि आपके उपकरण आपको बता रहे हैं, सुनिश्चित करें कि आप उन्हें ठीक से उपयोग कर रहे हैं हो सकता है।

+1

+1। कार्यक्रम समाप्ति पर गतिशील रूप से आवंटित स्मृति को साफ करने के लिए स्पष्ट रूप से लेखन कोड '{} 'से" सुनिश्चित करने के लिए स्वचालित चर को नष्ट कर दिया जाता है, "अतिरिक्त सुनिश्चित करने के लिए स्वचालित चर को नष्ट कर दिया जाता है। – user168715