Подтвердить что ты не робот

Как использовать valgrind для обнаружения утечек памяти?

Как использовать valgrind для поиска утечек памяти в программе?

Пожалуйста, помогите мне и опишите шаги для выполнения процедуры?

Я использую Ubuntu 10.04, и у меня есть программа a.c, пожалуйста, помогите мне.

4b9b3361

Ответ 1

Попробуйте следующее:

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

Пока valgrind установлен, он будет проходить через вашу программу и сообщать вам, что неправильно. Он может дать вам указатели и приблизительные места, где могут быть обнаружены утечки. Если вы segfault'ing, попробуйте запустить его через gdb.

Ответ 2

Вы можете запустить:

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

Ответ 3

Как запустить Valgrind

Я хотел бы основать на RageD отличный ответ, предоставив более подробное объяснение того, как эффективно использовать Valgrind и как разрешать утечки памяти. Чтобы не оскорблять OP, но для тех, кто пришел к этому вопросу и до сих пор не знаком с Linux - , вам может понадобиться установить Valgrind в вашей системе.

sudo apt-get install valgrind #mainly Ubuntu
sudo yum install valgrind     #RHEL, CentOS, Fedora, etc.

Valgrind легко используется для кода C/С++, но может даже использоваться для других языков при правильной настройке (см. this для Python).

Чтобы запустить valgrind, передайте исполняемый файл в качестве аргумента (вместе с любыми параметрами для программы).

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

Это приведет к созданию отчета в конце выполнения вашей программы, который (надеюсь) выглядит следующим образом:

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)

Посмотрим также на код C, который я написал:

#include <stdlib.h>

int main() {
    char* string = malloc(5 * sizeof(char)); //ERROR: 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)

Valgrind указал нам на точную строку кода, вызывающую утечку памяти!


Методы отладки утечек памяти и ошибок

  • Используйте www.cplusplus.com! Он имеет отличную документацию по функциям C/С++.
  • Общие рекомендации по утечкам памяти:
    • Убедитесь, что ваша динамически выделенная память действительно освобождается.
    • Не выделяйте память и не забывайте назначать указатель.
    • Не перезаписывайте указатель с новым, если не освобождена старая память.
  • Иногда Valgrind не всегда указывает точно, где ваша ошибка. Иногда у вас много ошибок, и один из них разрешает каскад других.
    • Перечислите функции в вашем коде, которые зависят от/зависят от "оскорбительного" кода, который имеет ошибку памяти. Следуйте за выполнением программы (возможно, даже в gdb возможно), и ищите ошибки предварительного условия/постусловия.
    • Попробуйте прокомментировать "оскорбительный" блок кода (в пределах разумности, поэтому ваш код все еще компилируется). Если ошибка Valgrind исчезнет, ​​вы обнаружили, где она находится.
  • Если все остальное не удается, попробуйте найти его. У Valgrind есть документация тоже!

Взгляд на общие утечки и ошибки

Следите за указателями

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

Вальгринд указывает нам на прокомментированную строку выше. Посмотрите на последнюю итерацию, которая есть *(destination + 26) = *(source + 26);. Однако *(source + 26) снова выходит за пределы, аналогично недействительной записи. Неверные чтения также являются общим результатом ошибок "один за другим". Посмотрите на правую сторону операции назначения.