Come faccio a usare valgrind per trovare perdite di memoria?

Come faccio a usare valgrind per trovare le perdite di memoria in un programma?

Per favore qualcuno mi aiuti e descriva i passaggi per eseguire la procedura?

Sto usando Ubuntu 10.04 e ho un programma ac , per favore aiutatemi.

Prova questo:

valgrind --leak-check=full -v ./your_program

Finché valgrind è installato, passerà attraverso il tuo programma e ti dirà cosa c’è che non va. Può darti indicazioni e luoghi approssimativi in ​​cui è ansible trovare le tue perdite. Se stai segfault, prova a eseguirlo tramite gdb .

Come eseguire Valgrind

Vorrei creare una spiegazione più dettagliata su come utilizzare efficacemente Valgrind e su come risolvere le perdite di memoria. Per non insultare l’OP, ma per coloro che vengono a questa domanda e sono ancora nuovi a Linux , potresti dover installare Valgrind sul tuo sistema.

 sudo apt install valgrind # Ubuntu, Debian, etc. sudo yum install valgrind # RHEL, CentOS, Fedora, etc. 

Valgrind è facilmente utilizzabile per il codice C / C ++, ma può anche essere usato per altri linguaggi se configurato correttamente (vedere questo per Python).

Per eseguire valgrind , passare l’eseguibile come argomento (insieme ai parametri del programma).

 valgrind --leak-check=full \ --show-leak-kinds=all \ --track-origins=yes \ --verbose \ --log-file=valgrind-out.txt \ ./executable exampleParam1 

Questo produrrà un report alla fine dell’esecuzione del programma che (si spera) assomigli a questo:

 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) 

Ho una perdita, ma DOVE ?

Quindi, hai una perdita di memoria, e Valgrind non sta dicendo nulla di significativo. Forse, qualcosa del genere:

 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) 

Diamo un’occhiata anche al codice C che ho scritto:

 #include  int main() { char* string = malloc(5 * sizeof(char)); //LEAK: not freed! return 0; } 

Bene, c’erano 5 byte persi. Come è successo? Il rapporto di errore dice solo main e malloc . In un programma più ampio, sarebbe seriamente problematico dare la caccia. Questo è dovuto al modo in cui è stato compilato l’eseguibile . Possiamo effettivamente ottenere dettagli linea per linea su cosa è andato storto. Ricompila il tuo programma con un flag di debug (sto usando gcc qui):

 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 

Ora con questa build di debug, Valgrind punta alla riga esatta del codice che alloca la memoria che è trapelata! (La formulazione è importante: potrebbe non essere esattamente dove si trova la tua perdita, ma cosa è trapelato. La traccia ti aiuta a trovare dove .)

 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) 

Tecniche per il debug di perdite di memoria ed errori

  • Utilizza http://www.cplusplus.com ! Ha un’ottima documentazione sulle funzioni C / C ++.
  • Consigli generali per perdite di memoria:
    • Assicurati che la tua memoria allocata dynamicmente venga liberata.
    • Non allocare memoria e dimenticare di assegnare il puntatore.
    • Non sovrascrivere un puntatore con uno nuovo a meno che la vecchia memoria non venga liberata.
  • Consigli generali per errori di memoria:
    • Accedi e scrivi su indirizzi e indici di tua proprietà. Gli errori di memoria sono diversi dalle perdite; spesso IndexOutOfBoundsException problemi di tipo IndexOutOfBoundsException .
    • Non accedere o scrivere in memoria dopo averlo liberato.
  • A volte Valgrind non indica sempre esattamente dove si trova il tuo errore. A volte hai un sacco di errori e la risoluzione di uno di loro risolve una cascata di altri.
    • Elencare le funzioni nel codice che dipendono da / dipendono dal codice “offendente” che ha l’errore di memoria. Segui l’esecuzione del programma (forse anche in gdb ) e cerca gli errori di condizionamento / postcondizionamento.
    • Prova a commentare il blocco di codice “offendente” (entro limiti ragionevoli, quindi il tuo codice è ancora compilato). Se l’errore Valgrind scompare, hai trovato dov’è.
  • Se tutto il resto fallisce, prova a cercarlo. Valgrind ha anche la documentazione !

Uno sguardo a perdite ed errori comuni

Guarda i tuoi suggerimenti

 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) 

E il codice:

 #include  #include  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; } 

Come assistente insegnante, ho visto spesso questo errore. Lo studente fa uso di una variabile locale e si dimentica di aggiornare il puntatore originale. L’errore qui sta notando che realloc può effettivamente spostare la memoria allocata da qualche altra parte e modificare la posizione del puntatore. Lasciamo quindi resizeArray senza dire a array->data dove è stato spostato l’array.

Scrittura non valida

 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) 

E il codice:

 #include  #include  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; } 

Si noti che Valgrind ci indirizza alla riga di codice commentata sopra. La matrice della dimensione 26 è indicizzata [0,25], motivo per cui *(alphabet + 26) è una scrittura non valida: è fuori limite. Una scrittura non valida è un risultato comune di errori "off-one". Guarda il lato sinistro della tua operazione di assegnazione.

Lettura non valida

 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) 

E il codice:

 #include  #include  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 ci indica la riga sopra commentata. Guarda l'ultima iterazione qui, che è
*(destination + 26) = *(source + 26); . Tuttavia, *(source + 26) è nuovamente fuori dai limiti, analogamente alla scrittura non valida. Anche le letture non valide sono un risultato comune degli errori "off-one". Guarda il lato destro della tua operazione di assegnazione.


Il topia Open Source (U / Dys)

Come faccio a sapere quando la perdita è mia? Come trovo la mia perdita quando sto usando il codice di qualcun altro? Ho trovato una perdita che non è mia; dovrei fare qualcosa? Tutte sono domande legittime. In primo luogo, 2 esempi del mondo reale che mostrano 2 classi di incontri comuni.

Jansson : una libreria JSON

 #include  #include  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; } 

Questo è un programma semplice: legge una stringa JSON e la analizza. In preparazione, usiamo le chiamate alle librerie per fare il parsing per noi. Jansson rende dinamiche le allocazioni necessarie poiché JSON può contenere strutture nidificate di se stesso. Tuttavia, questo non significa che decref o " decref " la memoria che ci è stata data da ogni funzione. In effetti, questo codice che ho scritto sopra getta sia una "lettura non valida" che una "scrittura non valida". Questi errori decref quando si estrae la linea decref per il value .

Perché? Il value variabile è considerato un "riferimento preso in prestito" nell'API Jansson. Jansson tiene traccia della sua memoria per te e devi semplicemente decref strutture JSON indipendentemente l'una dall'altra. La lezione qui: leggi la documentazione . Veramente. A volte è difficile da capire, ma ti stanno dicendo perché queste cose accadono. Invece, abbiamo domande su questo errore di memoria.

SDL : una libreria di grafica e giochi

 #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; } 

Cosa c'è di sbagliato con questo codice ? Invia costantemente ~ 212 KiB di memoria per me. Prenditi un momento per pensarci. Accendiamo SDL e poi disattiviamo. Risposta? Non c'è niente di sbagliato.

All'inizio potrebbe sembrare strano . A dire il vero, la grafica è disordinata ea volte devi accettare alcune perdite come parte della libreria standard. La lezione qui: non è necessario sedare ogni perdita di memoria . A volte hai solo bisogno di sopprimere le perdite perché sono noti problemi di cui non puoi fare nulla . (Questo non è il mio permesso di ignorare le tue fughe!)

Risposte al vuoto

Come faccio a sapere quando la perdita è mia?
È. (Sicuro al 99%, comunque)

Come trovo la mia perdita quando sto usando il codice di qualcun altro?
È probabile che qualcun altro l'abbia già trovato. Prova Google! Se fallisce, usa le abilità che ti ho dato sopra. Se ciò non riesce e per lo più si vedono le chiamate API e una piccola traccia dello stack, vedere la domanda successiva.

Ho trovato una perdita che non è mia; dovrei fare qualcosa?
Sì! La maggior parte delle API ha modi per segnalare bug e problemi. Usali! Aiuta a restituire gli strumenti che stai utilizzando nel tuo progetto!


Ulteriori letture

Grazie per essere rimasto con me così a lungo. Spero che tu abbia imparato qualcosa, visto che ho cercato di seguire l'ampio spettro di persone che arrivano a questa risposta. Alcune cose spero che tu abbia chiesto lungo la strada: come funziona l'allocatore di memoria di C? Che cos'è in realtà una perdita di memoria e un errore di memoria? Come sono diversi dai segfault? Come funziona Valgrind? Se tu avessi qualcuno di questi, per favore nutrite la vostra curiosità:

  • Maggiori informazioni su malloc , l'allocatore di memoria di C
  • Definizione di un errore di segmentazione
  • Definizione di una perdita di memoria
  • Definizione di un errore di accesso alla memoria
  • Come funziona Valgrind?

Puoi eseguire:

 valgrind --leak-check=full --log-file="logfile.out" -v [your_program(and its arguments)]