फिर भी Valgrind द्वारा पाया जा सकने योग्य रिसाव


154

इस ब्लॉक में उल्लिखित सभी कार्य पुस्तकालय के कार्य हैं। मैं इस स्मृति रिसाव को कैसे ठीक कर सकता हूं?

इसे " स्टिल रीचेबल " श्रेणी के अंतर्गत सूचीबद्ध किया गया है । (4 और हैं, जो बहुत समान हैं, लेकिन अलग-अलग आकार के हैं)

 630 bytes in 1 blocks are still reachable in loss record 5 of 5
    at 0x4004F1B: calloc (vg_replace_malloc.c:418)
    by 0x931CD2: _dl_new_object (dl-object.c:52)
    by 0x92DD36: _dl_map_object_from_fd (dl-load.c:972)
    by 0x92EFB6: _dl_map_object (dl-load.c:2251)
    by 0x939F1B: dl_open_worker (dl-open.c:255)
    by 0x935965: _dl_catch_error (dl-error.c:178)
    by 0x9399C5: _dl_open (dl-open.c:584)
    by 0xA64E31: do_dlopen (dl-libc.c:86)
    by 0x935965: _dl_catch_error (dl-error.c:178)
    by 0xA64FF4: __libc_dlopen_mode (dl-libc.c:47)
    by 0xAE6086: pthread_cancel_init (unwind-forcedunwind.c:53)
    by 0xAE61FC: _Unwind_ForcedUnwind (unwind-forcedunwind.c:126)

कैच: एक बार जब मैंने अपना कार्यक्रम चलाया, तो इसने कोई मेमोरी लीक नहीं की, लेकिन इसके वालग्राइंड आउटपुट में एक अतिरिक्त लाइन थी, जो पहले मौजूद थी:

मूनमैप () के कारण 0x5296fa0-0x52af438 पर /lib/libgcc_s-4.4.4-20100630.so.1 में जिम जाने

यदि रिसाव को ठीक नहीं किया जा सकता है, तो क्या कोई समझा सकता है कि मुनमैप () लाइन Valgrind को 0 "अभी भी पहुंच योग्य" लीक की रिपोर्ट करने का कारण बनता है?

संपादित करें:

यहाँ एक न्यूनतम परीक्षण नमूना है:

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

void *runner(void *param) {
    /* some operations ... */
    pthread_exit(NULL);
}

int n;

int main(void) {

    int i;
    pthread_t *threadIdArray;

    n=10; /* for example */

    threadIdArray = malloc((n+n-1)*sizeof(pthread_t));  

    for(i=0;i<(n+n-1);i++) {
        if( pthread_create(&threadIdArray[i],NULL,runner,NULL) != 0 ) {
            printf("Couldn't create thread %d\n",i);
            exit(1);
        }
    }


    for(i=0;i<(n+n-1);i++) {
        pthread_join(threadIdArray[i],NULL);
    }

    free(threadIdArray);

    return(0);
}

साथ दौड़ो:

valgrind -v --leak-check=full --show-reachable=yes ./a.out

जवाबों:


378

"मेमोरी लीक" को परिभाषित करने का एक से अधिक तरीका है। विशेष रूप से, "मेमोरी लीक" की दो प्राथमिक परिभाषाएं हैं जो प्रोग्रामर के बीच आम उपयोग में हैं।

"मेमोरी लीक" की पहली आमतौर पर इस्तेमाल की जाने वाली परिभाषा है, "मेमोरी को आवंटित किया गया था और कार्यक्रम समाप्त होने से पहले बाद में मुक्त नहीं किया गया था।" हालांकि, कई प्रोग्रामर (ठीक ही) का तर्क मेमोरी लीक है कि इस परिभाषा फिट वास्तव में समस्या का किसी भी प्रकार का पैदा नहीं करते, और इसलिए नहीं माना जाना चाहिए कि कुछ प्रकार के सच "मेमोरी लीक"।

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

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

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

संभवतः एकमात्र समय यह सुनिश्चित करने के लिए उपयोगी है कि सभी आवंटन में "फ़्रीज़" का मिलान होता है यदि आपके रिसाव का पता लगाने वाले उपकरण यह नहीं बता सकते हैं कि कौन से ब्लॉक "अभी भी उपलब्ध हैं" (लेकिन वेलग्रिंड ऐसा कर सकते हैं) या यदि आपका ऑपरेटिंग सिस्टम सभी को पुनः प्राप्त नहीं करता है एक समाप्ति प्रक्रिया की मेमोरी (सभी प्लेटफॉर्म जो वैलेग्रिंड को ऐसा करने के लिए पोर्ट किया गया है)।


क्या आप यह पता लगा सकते हैं कि मूनमैप () क्या कर रहा है जो "अभी भी पहुंच योग्य" ब्लॉक को गायब कर देता है?

3
@ क्रिप्टो: ऐसा हो सकता है कि munmapसाझा वस्तु को उतारने के परिणामस्वरूप किया जाता है। और साझा किए गए ऑब्जेक्ट द्वारा उपयोग किए जाने वाले सभी संसाधनों को अनलोड किए जाने से पहले मुक्त किया जा सकता है। यह समझा सकता है कि मामले में "अभी भी पुनर्खरीद" क्यों मुक्त हो रही है munmap। मैं यहाँ सिर्फ अटकलें लगा रहा हूँ, हालाँकि। सुनिश्चित करने के लिए कहने के लिए यहां पर्याप्त जानकारी नहीं है।
दान मोल्डिंग

3
एक मामला जहां "अभी भी पहुंच में है" मेमोरी को मेमोरी लीक माना जा सकता है: मान लें कि आपके पास एक हैश टेबल है जहां आप आवंटित मेमोरी को मूल्य के रूप में प्राप्त करने के लिए संकेत जोड़ते हैं। यदि आप मेज पर नई प्रविष्टियाँ डालते रहते हैं, लेकिन आप को हटाने और मुक्त करने की आवश्यकता नहीं है, तो यह अनिश्चित काल तक बढ़ सकता है, ढेर स्मृति घटना को लीक कर सकता है यदि वह स्मृति thecnically "अभी भी पहुंच योग्य" है। यह स्मृति रिसाव का मामला है जो आप जावा या अन्य कचरा एकत्र भाषाओं में हो सकते हैं।
लवेला

STL द्वारा बनाए गए "अभी भी पहुंच योग्य" ब्लॉक के बारे में सामान्य प्रश्नों के उत्तर में यह उत्तर भी देखें। valgrind.org/docs/manual/faq.html#faq.reports
जॉन पेरी

5
"कई प्रोग्रामर (सही रूप से) तर्क देते हैं कि [लीक हुई मेमोरी] वास्तव में [ए] समस्या पैदा नहीं करती है, और इसलिए इसे सच्ची मेमोरी लीक नहीं माना जाना चाहिए" - योग्य ... स्मृति रिसाव के उस प्रकार के साथ एक मूल DLL बनाएँ, और फिर जावा या .Net इसका सेवन करें। जावा और। नेट लोड और एक कार्यक्रम के जीवन के दौरान हजारों बार DLL को उतारना। हर बार जब DLL को पुनः लोड किया जाता है तो यह थोड़ी अधिक मेमोरी को लीक कर देगा। लंबे समय तक चलने वाले कार्यक्रम अंततः स्मृति से बाहर निकल जाएंगे। यह डेबियन के OpenJDK मेंटेनर को पागल बना देता है। उन्होंने ओपनएसएसएल मेलिंग सूची में वही कहा था जब हम ओपनएसएसएल की "सौम्य" मेमोरी लीक पर चर्चा कर रहे थे।
jww

10

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

जब तक आप कॉल नहीं करते तब तक उस धागे की निकास स्थिति की जानकारी उपलब्ध रहती है pthread_join। इस प्रकार, मेमोरी को प्रोग्राम समाप्ति पर एक नुकसान रिकॉर्ड में रखा जाता है, लेकिन यह अभी भी उपलब्ध है क्योंकि आप pthread_joinइसे एक्सेस करने के लिए उपयोग कर सकते हैं।

यदि यह विश्लेषण सही है, तो या तो इन थ्रेड्स को अलग करके लॉन्च करें, या अपने प्रोग्राम को समाप्त करने से पहले इनसे जुड़ें।

संपादित करें : मैंने आपका नमूना कार्यक्रम (कुछ स्पष्ट सुधारों के बाद) चलाया और मेरे पास त्रुटियाँ नहीं हैं लेकिन निम्नलिखित हैं

==18933== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 4 from 4)
--18933-- 
--18933-- used_suppression:      2 dl-hack3-cond-1
--18933-- used_suppression:      2 glibc-2.5.x-on-SUSE-10.2-(PPC)-2a

चूँकि वह dl-चीज़ जो आप देखते हैं उससे बहुत मिलती है, मुझे लगता है कि आपको एक ज्ञात समस्या दिखाई देती है जिसका समाधान एक दमन फ़ाइल के रूप में है valgrind। शायद आपका सिस्टम अद्यतित नहीं है, या आपका वितरण इन चीजों को बनाए नहीं रखता है। (मेरा ubuntu 10.4, 64bit है)


मुझे आपकी तरह ही 0 त्रुटियां हो रही हैं। कृपया "लीक" के बारे में जानकारी के लिए लीक सारांश देखें।

@ क्रिप्टो: मुझे समझ नहीं आता। आपका मतलब है कि आपके पास मेरे जैसे ही हैं?
जेन्स गस्टेड

used_suppression: 14 dl-hack3-cond-1 <- यही मुझे मिलता है

6

आप still reachableइसका मतलब नहीं समझते हैं ।

कुछ भी still reachableहै नहीं एक रिसाव। आपको इसके बारे में कुछ भी करने की आवश्यकता नहीं है।


24
यह वाल्ग्रिंड द्वारा प्रदान की गई अन्य क्रिया के साथ-साथ तकनीकी रूप से गलत है। स्मृति कार्यक्रम से बाहर निकलने पर "अभी भी पहुंच योग्य" थी और इस तरह संभवतः एक रिसाव। क्या होगा यदि आप आरटीओएस पर चलने के लिए कोड डिबगिंग कर रहे थे जो प्रोग्राम से बाहर निकलने के बाद मेमोरी को अच्छी तरह से साफ नहीं करता है?
टॉयमेकरिइ 19

4
दुर्भाग्य से, यह हमेशा सच नहीं है। उदाहरण के लिए लॉस्ट फाइल डिस्क्रिप्टर मेमोरी लीक के रूप में गिना जा सकता है, लेकिन वैधता उन्हें "अभी भी पहुंच योग्य" के रूप में वर्गीकृत करती है, संभवतः क्योंकि पॉइंटर्स उनके लिए अग्रणी सिस्टम टेबल के भीतर अभी भी सुलभ हैं। लेकिन डिबगिंग के उद्देश्य के लिए, वास्तविक निदान एक "मेमोरी लीक" है।
सियान

लॉस्ट फ़ाइल डिस्क्रिप्टर परिभाषा द्वारा मेमोरी लीक नहीं हैं । शायद आप खोए हुए FILEसंकेत के बारे में बात कर रहे हैं ?
रूसी

6

यहाँ "अभी भी पहुंच योग्य" की एक उचित व्याख्या है:

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

स्थानीय चर जो आवंटित किए गए हैं और फ्री होल्ड नहीं हैं वे लगभग हमेशा लीक होते हैं।

यहाँ एक उदाहरण है

int foo(void)
{
    static char *working_buf = NULL;
    char *temp_buf;
    if (!working_buf) {
         working_buf = (char *) malloc(16 * 1024);
    }
    temp_buf = (char *) malloc(5 * 1024);

    ....
    ....
    ....

}

Valgrind वर्किंग_buf को "अभी भी पहुंच योग्य - 16k" और temp_buf के रूप में "निश्चित रूप से खो गया - 5k" के रूप में रिपोर्ट करेगा।


-1

भविष्य के पाठकों के लिए, "स्टिल रीचेबल" का मतलब हो सकता है कि आप किसी फ़ाइल की तरह कुछ बंद करना भूल गए हों। हालांकि यह मूल प्रश्न में ऐसा नहीं लगता है, आपको हमेशा यह सुनिश्चित करना चाहिए कि आपने ऐसा किया है।

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