मैं किसी प्रोग्राम में मेमोरी लीक को खोजने के लिए वेलग्रिंड का उपयोग कैसे करूं?
कृपया किसी ने मेरी मदद की और प्रक्रिया को पूरा करने के चरणों का वर्णन किया?
मैं उबंटू 10.04 का उपयोग कर रहा हूं और मेरा एक कार्यक्रम है a.c
, कृपया मेरी मदद करें।
मैं किसी प्रोग्राम में मेमोरी लीक को खोजने के लिए वेलग्रिंड का उपयोग कैसे करूं?
कृपया किसी ने मेरी मदद की और प्रक्रिया को पूरा करने के चरणों का वर्णन किया?
मैं उबंटू 10.04 का उपयोग कर रहा हूं और मेरा एक कार्यक्रम है a.c
, कृपया मेरी मदद करें।
जवाबों:
ओपी का अपमान करने के लिए नहीं, लेकिन उन लोगों के लिए जो इस सवाल पर आते हैं और अभी भी लिनक्स के लिए नए हैं- आपको अपने सिस्टम पर Valgrind स्थापित करना पड़ सकता है ।
sudo apt install valgrind # Ubuntu, Debian, etc.
sudo yum install valgrind # RHEL, CentOS, Fedora, etc.
Valgrind C / C ++ कोड के लिए आसानी से प्रयोग करने योग्य है, लेकिन अन्य भाषाओं के लिए भी उपयोग किया जा सकता है जब ठीक से कॉन्फ़िगर किया गया हो ( यह पायथन के लिए देखें )।
Valgrind चलाने के लिए, निष्पादन योग्य को एक तर्क के रूप में (कार्यक्रम के किसी भी पैरामीटर के साथ) पास करें।
valgrind --leak-check=full \
--show-leak-kinds=all \
--track-origins=yes \
--verbose \
--log-file=valgrind-out.txt \
./executable exampleParam1
झंडे, संक्षेप में हैं:
--leak-check=full
: "प्रत्येक व्यक्तिगत रिसाव को विस्तार से दिखाया जाएगा"--show-leak-kinds=all
: "पूर्ण" रिपोर्ट में सभी "निश्चित, अप्रत्यक्ष, संभव, पहुंच योग्य" लीक प्रकार दिखाएं।--track-origins=yes
: गति पर अनुकूल उपयोगी आउटपुट। यह असमान मूल्यों की उत्पत्ति को ट्रैक करता है, जो मेमोरी त्रुटियों के लिए बहुत उपयोगी हो सकता है। मान लें कि यदि Valgrind अस्वीकार्य रूप से धीमा है।--verbose
: आप अपने कार्यक्रम के असामान्य व्यवहार के बारे में बता सकते हैं। अधिक वाचालता के लिए दोहराएं।--log-file
: फ़ाइल में लिखें। उपयोगी जब आउटपुट टर्मिनल स्पेस से अधिक हो।अंत में, आप एक Valgrind रिपोर्ट देखना चाहेंगे जो इस तरह दिखाई देती है:
HEAP SUMMARY:
in use at exit: 0 bytes in 0 blocks
total heap usage: 636 allocs, 636 frees, 25,393 bytes allocated
All heap blocks were freed -- no leaks are possible
ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
तो, आपके पास स्मृति रिसाव है, और Valgrind कुछ भी सार्थक नहीं कह रहा है। शायद, कुछ इस तरह:
5 bytes in 1 blocks are definitely lost in loss record 1 of 1
at 0x4C29BE3: malloc (vg_replace_malloc.c:299)
by 0x40053E: main (in /home/Peri461/Documents/executable)
आइए मेरे द्वारा लिखे गए सी कोड पर एक नज़र डालें:
#include <stdlib.h>
int main() {
char* string = malloc(5 * sizeof(char)); //LEAK: not freed!
return 0;
}
खैर, वहाँ 5 बाइट्स खो गए थे। यह कैसे हुआ? त्रुटि रिपोर्ट सिर्फ कहते हैं
main
और malloc
। एक बड़े कार्यक्रम में, जो नीचे शिकार करने के लिए गंभीर रूप से परेशानी होगी। इसका कारण यह है कि निष्पादन योग्य कैसे संकलित किया गया था । हम वास्तव में लाइन-बाय-लाइन विवरण प्राप्त कर सकते हैं कि क्या गलत हुआ। अपने प्रोग्राम को डीबग फ़्लैग के साथ पुन: संयोजित करें (मैं gcc
यहाँ उपयोग कर रहा हूँ ):
gcc -o executable -std=c11 -Wall main.c # suppose it was this at first
gcc -o executable -std=c11 -Wall -ggdb3 main.c # add -ggdb3 to it
अब इस डिबग बिल्ड के साथ, Valgrind कोड की सटीक लाइन को इंगित करता है जो कि लीक हुई मेमोरी को आवंटित करता है! (शब्दांकन महत्वपूर्ण है: यह ठीक नहीं हो सकता है कि आपका रिसाव कहां है, लेकिन जो लीक हुआ है। ट्रेस आपको यह पता लगाने में मदद करता है कि कहां है ।)
5 bytes in 1 blocks are definitely lost in loss record 1 of 1
at 0x4C29BE3: malloc (vg_replace_malloc.c:299)
by 0x40053E: main (main.c:4)
IndexOutOfBoundsException
समस्याएं टाइप करते हैं।कभी-कभी आपकी लीक / त्रुटियों को एक दूसरे से जोड़ा जा सकता है, एक आईडीई की तरह बहुत कुछ पता चलता है कि आपने अभी तक एक समापन ब्रैकेट टाइप नहीं किया है। एक मुद्दे को हल करने से दूसरों को हल किया जा सकता है, इसलिए एक को देखें जो एक अच्छा अपराधी दिखता है और इन विचारों में से कुछ को लागू करता है:
gdb
), और पूर्व शर्त / पोस्टकंडिशन त्रुटियों की तलाश करें। आवंटित स्मृति के जीवनकाल पर ध्यान केंद्रित करते हुए अपने कार्यक्रम के निष्पादन का पता लगाना है।60 bytes in 1 blocks are definitely lost in loss record 1 of 1
at 0x4C2BB78: realloc (vg_replace_malloc.c:785)
by 0x4005E4: resizeArray (main.c:12)
by 0x40062E: main (main.c:19)
और कोड:
#include <stdlib.h>
#include <stdint.h>
struct _List {
int32_t* data;
int32_t length;
};
typedef struct _List List;
List* resizeArray(List* array) {
int32_t* dPtr = array->data;
dPtr = realloc(dPtr, 15 * sizeof(int32_t)); //doesn't update array->data
return array;
}
int main() {
List* array = calloc(1, sizeof(List));
array->data = calloc(10, sizeof(int32_t));
array = resizeArray(array);
free(array->data);
free(array);
return 0;
}
एक शिक्षण सहायक के रूप में, मैंने इस गलती को अक्सर देखा है। छात्र एक स्थानीय चर का उपयोग करता है और मूल सूचक को अद्यतन करने के लिए भूल जाता है। यहां त्रुटि ध्यान देने योग्य है जो realloc
वास्तव में आवंटित मेमोरी को कहीं और स्थानांतरित कर सकती है और पॉइंटर के स्थान को बदल सकती है। फिर हम resizeArray
यह बताए बिना
छोड़ देते हैं array->data
कि सरणी को कहां स्थानांतरित किया गया था।
1 errors in context 1 of 1:
Invalid write of size 1
at 0x4005CA: main (main.c:10)
Address 0x51f905a is 0 bytes after a block of size 26 alloc'd
at 0x4C2B975: calloc (vg_replace_malloc.c:711)
by 0x400593: main (main.c:5)
और कोड:
#include <stdlib.h>
#include <stdint.h>
int main() {
char* alphabet = calloc(26, sizeof(char));
for(uint8_t i = 0; i < 26; i++) {
*(alphabet + i) = 'A' + i;
}
*(alphabet + 26) = '\0'; //null-terminate the string?
free(alphabet);
return 0;
}
ध्यान दें कि Valgrind हमें ऊपर कोड की टिप्पणी की गई पंक्ति की ओर इंगित करता है। आकार 26 की श्रेणी अनुक्रमित है [0,25] जिसके कारण *(alphabet + 26)
एक अमान्य लेखन है - यह सीमा से बाहर है। अमान्य लेखन ऑफ-बाय-वन त्रुटियों का एक सामान्य परिणाम है। अपने असाइनमेंट ऑपरेशन के बाईं ओर देखें।
1 errors in context 1 of 1:
Invalid read of size 1
at 0x400602: main (main.c:9)
Address 0x51f90ba is 0 bytes after a block of size 26 alloc'd
at 0x4C29BE3: malloc (vg_replace_malloc.c:299)
by 0x4005E1: main (main.c:6)
और कोड:
#include <stdlib.h>
#include <stdint.h>
int main() {
char* destination = calloc(27, sizeof(char));
char* source = malloc(26 * sizeof(char));
for(uint8_t i = 0; i < 27; i++) {
*(destination + i) = *(source + i); //Look at the last iteration.
}
free(destination);
free(source);
return 0;
}
Valgrind हमें ऊपर टिप्पणी की गई रेखा की ओर इशारा करता है। यहां अंतिम पुनरावृत्ति को देखें, जो है
*(destination + 26) = *(source + 26);
। हालांकि, *(source + 26)
फिर से सीमा से बाहर है, इसी तरह से अमान्य लिखना। अमान्य रीड ऑफ़-ऑफ-वन त्रुटियां भी एक सामान्य परिणाम हैं। अपने असाइनमेंट ऑपरेशन के दाईं ओर देखें।
मुझे कैसे पता चलेगा कि रिसाव मेरा है? जब मैं किसी और के कोड का उपयोग कर रहा हूं तो मुझे अपना रिसाव कैसे मिलेगा? मुझे एक रिसाव मिला जो मेरा नहीं है; क्या मुझे कुछ करना चाहिए? सभी वैध प्रश्न हैं। सबसे पहले, 2 वास्तविक दुनिया के उदाहरण जो आम मुठभेड़ों के 2 वर्गों को दिखाते हैं।
#include <jansson.h>
#include <stdio.h>
int main() {
char* string = "{ \"key\": \"value\" }";
json_error_t error;
json_t* root = json_loads(string, 0, &error); //obtaining a pointer
json_t* value = json_object_get(root, "key"); //obtaining a pointer
printf("\"%s\" is the value field.\n", json_string_value(value)); //use value
json_decref(value); //Do I free this pointer?
json_decref(root); //What about this one? Does the order matter?
return 0;
}
यह एक सरल कार्यक्रम है: यह JSON स्ट्रिंग पढ़ता है और इसे पार्स करता है। मेकिंग में, हम अपने लिए पार्सिंग करने के लिए लाइब्रेरी कॉल का उपयोग करते हैं। Jansson गतिशील रूप से आवश्यक आवंटन करता है क्योंकि JSON में स्वयं के नेस्टेड संरचनाएँ हो सकती हैं। हालांकि, इसका मतलब यह नहीं है कि हम decref
हर फंक्शन से हमें दी गई मेमोरी को "फ्री" या "फ्री" करते हैं। वास्तव में, यह कोड मैंने ऊपर लिखा है, दोनों एक "अमान्य रीड" और एक "अमान्य लेखन"। जब आप के लिए decref
लाइन निकालते हैं तो वे त्रुटियां दूर हो जाती हैं value
।
क्यों? चर value
को जैनसन एपीआई में "उधार संदर्भ" माना जाता है। Jansson आपके लिए इसकी मेमोरी का ट्रैक रखता है, और आपको बस decref
JSON संरचनाओं को एक दूसरे से स्वतंत्र रखना है । यहाँ सबक:
प्रलेखन पढ़ें । वास्तव में। कभी-कभी यह समझना मुश्किल होता है, लेकिन वे आपको बता रहे हैं कि ये चीजें क्यों होती हैं। इसके बजाय, इस मेमोरी त्रुटि के बारे में हमारे पास
मौजूदा प्रश्न हैं।
#include "SDL2/SDL.h"
int main(int argc, char* argv[]) {
if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO) != 0) {
SDL_Log("Unable to initialize SDL: %s", SDL_GetError());
return 1;
}
SDL_Quit();
return 0;
}
इस कोड में क्या गलत है ? यह मेरे लिए लगातार ~ 212 KiB मेमोरी लीक करता है। इसके बारे में सोचने के लिए कुछ समय निकालें। हम एसडीएल को चालू करते हैं और फिर बंद कर देते हैं। उत्तर? कुछ भी गलत नहीं है।
यह पहली बार में अजीब लग सकता है । सच कहा जाए, तो ग्राफिक्स गड़बड़ हैं और कभी-कभी आपको मानक पुस्तकालय का हिस्सा होने के नाते कुछ लीक को स्वीकार करना पड़ता है। यहां सबक: आपको हर मेमोरी लीक को छोड़ने की आवश्यकता नहीं है । कभी-कभी आपको केवल लीक को दबाने की आवश्यकता होती है क्योंकि वे ज्ञात मुद्दे हैं जिनके बारे में आप कुछ नहीं कर सकते हैं । (यह आपकी खुद की लीक को अनदेखा करने की मेरी अनुमति नहीं है!)
मुझे कैसे पता चलेगा कि रिसाव मेरा है?
यह है। (99% यकीन है, वैसे भी)
जब मैं किसी और के कोड का उपयोग कर रहा हूं तो मुझे अपना रिसाव कैसे मिलेगा?
संभावना है कि कोई और पहले से ही मिल जाए। Google को आज़माएं! यदि वह विफल रहता है, तो मेरे द्वारा दिए गए कौशल का उपयोग करें। यदि वह विफल हो जाता है और आप ज्यादातर एपीआई कॉल और अपने स्वयं के स्टैक ट्रेस से थोड़ा देखते हैं, तो अगला प्रश्न देखें।
मुझे एक रिसाव मिला जो मेरा नहीं है; क्या मुझे कुछ करना चाहिए?
हाँ! अधिकांश एपीआई में बग और मुद्दों की रिपोर्ट करने के तरीके हैं। उन्हें इस्तेमाल करें! अपने प्रोजेक्ट में आपके द्वारा उपयोग किए जा रहे टूल को वापस देने में मदद करें!
मेरे साथ लंबे समय तक रहने के लिए धन्यवाद। मुझे आशा है कि आपने कुछ सीखा है, जैसा कि मैंने इस उत्तर पर पहुंचने वाले लोगों के व्यापक स्पेक्ट्रम के लिए प्रयास किया। कुछ चीजें जो मुझे आशा है कि आपने रास्ते में पूछी हैं: सी की मेमोरी एलोकेटर कैसे काम करती है? क्या वास्तव में एक स्मृति रिसाव और एक स्मृति त्रुटि है? वे segfaults से कैसे अलग हैं? Valgrind कैसे काम करता है? यदि आपके पास इनमें से कोई भी हो, तो कृपया अपनी जिज्ञासा को पूरा करें:
memcheck
उपकरण डिफ़ॉल्ट रूप से सक्षम है?
memcheck
डिफ़ॉल्ट टूल है:--tool=<toolname> [default: memcheck]
इसे इस्तेमाल करे:
valgrind --leak-check=full -v ./your_program
जब तक वेलग्रिंड इंस्टॉल हो जाता है तब तक यह आपके प्रोग्राम के माध्यम से जाएगा और आपको बताएगा कि क्या गलत है। यह आपको संकेत और अनुमानित स्थान दे सकता है जहां आपके लीक पाए जा सकते हैं। यदि आप segfault'ing कर रहे हैं, तो इसे माध्यम से चलाने का प्रयास करें gdb
।
your_program
== निष्पादन योग्य नाम या जो भी आदेश आप अपने आवेदन को चलाने के लिए उपयोग करते हैं।
तुम दौड़ सकते हो:
valgrind --leak-check=full --log-file="logfile.out" -v [your_program(and its arguments)]
आप निम्न रूप से .bashrc फ़ाइल में एक उपनाम बना सकते हैं
alias vg='valgrind --leak-check=full -v --track-origins=yes --log-file=vg_logfile.out'
इसलिए जब भी आप मेमोरी लीक की जांच करना चाहते हैं, तो बस करें
vg ./<name of your executable> <command line parameters to your executable>
यह वर्तमान निर्देशिका में एक Valgrind लॉग फ़ाइल उत्पन्न करेगा।