2010-03-18 16 views
23

सी और सी ++ में, एक पूर्ण सूचक को मुक्त करने के परिणामस्वरूप कुछ भी नहीं किया जाएगा।दो बार स्मृति को मुक्त करना

फिर भी, मैं लोगों को यह कहता हूं कि स्मृति "भ्रष्टाचार हो सकता है यदि आप" दो बार मुफ्त मेमोरी "करते हैं।

क्या यह सच है? जब आप दो बार मुफ्त मेमोरी करते हैं तो हुड के नीचे क्या चल रहा है?

+3

जब आप एक शून्य सूचक को मुक्त करते हैं तो कोई स्मृति मुक्त नहीं होती है। यदि आप दो बार * गैर-शून्य * पॉइंटर मुक्त करते हैं, तो स्मृति दो बार मुक्त हो जाती है, और यह एक समस्या है। – jalf

उत्तर

22
int *p = malloc(sizeof(int)); 
//value of p is now lets say 0x12345678 

*p = 2; 
free(p); //memory pointer is freed, but still value of p is 0x12345678 
     //now, if you free again, you get a crash or undefined behavior. 

तो, free पहली बार ing के बाद, आप p = NULL करना चाहिए, इसलिए यदि (किसी भी संयोग से), free(p) फिर से कहा जाता है, कुछ नहीं होगा। Why free crashes when called twice

+6

+1, भले ही मैं पॉइंटर को नल के ठीक बाद सेट करने में असहमत हूं, फिर भी एक स्थायी बग (दूसरी बार 'फ्री' को कॉल करना) को छिपा सकता है और मैं इसे कठिन और तेज़ी से विफल कर दूंगा बग छुपा से संभाला जा सकता है। –

+0

@ डेविड: मैं पूरी तरह से सहमत हूं, अगर सूचक पर दो बार 'फ्री' कहा जाता है, तो यह एक (कुछ हद तक) खराब कार्यान्वयन है। –

+1

@ डेविड: यह तब तक एक अच्छी रणनीति है जब तक आप जानते हैं कि 'मुक्त-दो बार' स्थितियों को कैसे डिबग करना है। यदि आप नहीं करते हैं, तो मैं मुक्त करने के बाद पॉइंटर को ठीक कर दूंगा और प्रत्येक 'मुक्त' कथन से ठीक पहले इसे शून्यता के लिए जांचूंगा। –

9

यह अनिर्धारित व्यवहार है, जिसके परिणामस्वरूप भ्रष्टाचार भ्रष्टाचार या अन्य गंभीर परिणाम हो सकते हैं।

free() एक शून्य सूचक के लिए बस अंदर पॉइंटर मूल्य की जांच करता है और लौटाता है। वह चेक दो बार ब्लॉक को मुक्त करने में मदद नहीं करेगा।

यहां आमतौर पर क्या होता है। ढेर कार्यान्वयन पते प्राप्त करता है और उस पते पर अपने स्वयं के सेवा डेटा को संशोधित करके ब्लॉक के "स्वामित्व" लेने का प्रयास करता है। ढेर कार्यान्वयन के आधार पर कुछ भी हो सकता है। शायद यह काम करता है और कुछ नहीं होता है, शायद सेवा डेटा दूषित हो गया है और आपको ढेर भ्रष्टाचार मिला है।

तो ऐसा मत करें। यह अपरिभाषित व्यवहार है। जो भी बुरी चीजें हो सकती हैं।

+0

मैं यह भी स्पष्ट रूप से कहूंगा कि एक पॉइंटर में 'मुक्त' नहीं है (अनिवार्य रूप से) इसके मूल्य को बदलता है और सामान्य रूप से यह 'मुक्त' के बाद शून्य नहीं होता है (यही कारण है कि दूसरा 'मुक्त' भ्रष्टाचार का कारण बनता है)। – Ari

4

हां, "अपरिभाषित व्यवहार" जो लगभग हमेशा एक दुर्घटना में परिणाम देता है। (परिभाषा के अनुसार "अपरिभाषित व्यवहार" का अर्थ है "कुछ भी", विभिन्न प्रकार की त्रुटियां अक्सर अनुमानित तरीकों से व्यवहार करती हैं। मुक्त() के मामले में, व्यवहार हमेशा सेगफॉल्ट या ओएस को संबंधित "स्मृति सुरक्षा त्रुटि" विशेषता है।)

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

char x; char* p=&x; free(p); // क्रैश।

+0

+1 क्रैश 101 वहां। – kenny

+3

आप अपरिभाषित व्यवहार के परिणामों पर बहुत आशावादी हैं। –

+0

मैं रोजर के साथ हूं।वास्तव में, कुछ बार मुक्त करने से लगभग किसी भी समय दुर्घटना में नतीजा होता है, जो मुक्त होता है, जो इसे ट्रैक करने के लिए सबसे कठिन बगों में से एक बनाता है। जवाब की शुद्धता के लिए –

2

मुक्त() को मुक्त कर देते स्मृति स्थान ptr, जो malloc के लिए पिछले एक कॉल द्वारा दिया गया है चाहिए द्वारा करने के लिए बताया(), calloc() या realloc()। अन्यथा, या यदि मुक्त (पीआरटी) पहले से ही पहले कहा गया है, तो अपरिभाषित व्यवहार होता है। यदि पीआरटी न्यूल है, तो कोई ऑपरेशन नहीं किया जाता है।

तो, आपको अपरिभाषित व्यवहार मिलता है, और कुछ भी हो सकता है।

1

1) गतिशील स्मृति के हैंडलिंग संकलक द्वारा नहीं किया जाता है:

यहाँ क्यों स्मृति में दो बार अपरिभाषित है मुक्त कराने के लिए है। रन-टाइम पुस्तकालय हैं जो इसका ख्याल रखते हैं। उदाहरण के लिए। : glibc malloc और free जैसे एपीआई प्रदान करता है, जो आंतरिक रूप से ढेर क्षेत्र को संभालने के लिए सिस्टम कॉल (sys_brk) बनाता है।

2) एक ही स्मृति को दो बार मुक्त करना इस तरह की स्थिति को संदर्भित करता है: मान लें कि आपके पास char * cptr है;

आप स्मृति का उपयोग करते हुए स्मृति आवंटित करते हैं: cptr = (char *) malloc (SIZE);

अब, जब आपको अब इस मेमोरी की आवश्यकता नहीं है, तो आप इसका उपयोग करके इसे मुक्त कर सकते हैं: मुफ्त (सीपीटीआर);

अब यहां क्या होता है सीपीयू द्वारा इंगित स्मृति स्मृति उपयोग के लिए नि: शुल्क है।

मान लीजिए कि कार्यक्रम में बाद के समय पर आप फिर से एक मुफ्त (सीपीटीआर) कहते हैं, तो यह मान्य स्थिति नहीं है। यह परिदृश्य जहां आप दो बार एक ही मेमोरी को मुक्त कर रहे हैं, उसे "स्मृति दो बार मुक्त करने" के रूप में जाना जाता है।

19

फ्रीिंग मेमोरी पॉइंटर को शून्य पर सेट नहीं करती है। पॉइंटर उस स्मृति को इंगित करता है जो इसका इस्तेमाल करता था, लेकिन अब स्वामित्व को हेप मैनेजर में स्थानांतरित कर दिया गया है।

ढेर मैनेजर तब से हो सकता है जब आपका पुराना पॉइंटर इंगित कर रहा है।

इसे फिर से मुक्त करना free(NULL) कहने जैसा नहीं है, और इसके परिणामस्वरूप अपरिभाषित व्यवहार होगा।

3

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

#include <stdio.h> 
#include <stdlib.h> 

int main(){ 
    int* ptr = (int*)malloc(sizeof(int)); 
    printf("Address before free: %p\n", ptr); 
    free(ptr); 
    printf("Address after free: %p\n", ptr); 
    return 0; 
} 

इस कार्यक्रम के आउटपुट:

Address before free: 0x950a008 
Address after free: 0x950a008 

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

4

दो बार मैं alway मुक्त स्मृति के लिए मैक्रो का उपयोग कर मुक्त बचने के लिए:

#ifdef FREEIF 
# undef FREEIF 
#endif 
#define FREEIF(_p) \ 
if(_p)    \ 
{      \ 
     free(_p); \ 
     _p = NULL; \ 
} 

इस मैक्रो सेट पी = शून्य सूचक झूलते से बचने के लिए।

+2

यह एक अच्छा हैक है लेकिन मैं वास्तविक कारण को ठीक करने की कोशिश करता हूं। यदि मुक्त() एक ही चर पर दो बार बुलाया जाता है, तो यह स्पष्ट रूप से एक बग है। – user206268

0

एक बार से अधिक स्मृति को मुक्त करने से खराब परिणाम हो सकते हैं। आप अपने कंप्यूटर के लिए क्या हो सकता है यह देखने के लिए कोड का यह टुकड़ा चला सकते हैं।

#include <stdio.h>  /* printf, scanf, NULL */ 
#include <stdlib.h>  /* malloc, free, rand */ 

int main() 


    { 
    int i,n; 
    char * buffer; 

    printf ("How long do you want the string? "); 
    scanf ("%d", &i); 

    buffer = (char*) malloc (i+1); 
    if (buffer==NULL) exit (1); 

    for (n=0; n<i; n++) 
      buffer[n]=rand()%26+'a'; 
    buffer[i]='\0'; 

    printf ("Random string: %s\n",buffer); 
    free (buffer); 
    free (buffer); 

    return 0; 
} 

सीएसपरसे जैसे कई मानक पुस्तकालय एक रैपर फ़ंक्शन का उपयोग करते हैं जो स्मृति समस्याओं को संभालता है। मैं समारोह यहां कॉपी:

/* wrapper for free */ 
    void *cs_free (void *p) 
    { 
     if (p) free (p) ;  /* free p if it is not already NULL */ 
     return (NULL) ;   /* return NULL to simplify the use of  

    } 

इस समारोह स्मृति के साथ मुद्दों को संभाल सकता है। कृपया ध्यान दें कि आपको इस शर्त का ख्याल रखना है कि कुछ मामलों में malloc NULL लौटाता है

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