Вы используете valgrind для тестирования вашей скомпилированной программы, а не исходного кода.
Тони
6
Ответ @RageD, приведенный ниже, правильный, почему вы его не принимаете?
Пратик Сингхал
1
Утечка вызвана чем-то, что вы не можете сделать - т.е. свободная выделенная память. Следовательно, Valgrind не может показать вам «где» утечка - только вы знаете, где выделенная память больше не требуется. Однако, сообщая вам, какое распределение не является свободным () d, отслеживая использование этой памяти через вашу программу, вы должны быть в состоянии определить, где она должна освободиться () d. Распространенной ошибкой является выход из функции без освобождения выделенной памяти.
Не для того, чтобы оскорблять ОП, но для тех, кто пришел к этому вопросу и все еще не знаком с Linux - вам, возможно, придется установить Valgrind в вашей системе.
sudo apt install valgrind # Ubuntu, Debian, etc.
sudo yum install valgrind # RHEL, CentOS, Fedora, etc.
Valgrind легко использовать для кода C / C ++, но при правильной настройке его можно использовать и для других языков (см. Это для Python).
Чтобы запустить Valgrind , передайте исполняемый файл в качестве аргумента (вместе с любыми параметрами в программу).
--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 allocatedAll 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)
У меня течь, но ГДЕ ?
Итак, у вас утечка памяти, и Вальгринд не говорит ничего значимого. Возможно, что-то вроде этого:
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));//LEAK: not freed!return0;}
Ну, было потеряно 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)
Методы отладки утечек памяти и ошибок
Воспользуйтесь www.cplusplus.com ! Он имеет отличную документацию по функциям C / C ++.
Общие советы по утечке памяти:
Убедитесь, что ваша динамически выделенная память действительно освобождается.
Не выделяйте память и забудьте назначить указатель.
Не перезаписывайте указатель новым, если старая память не освобождена.
Общие советы по ошибкам памяти:
Получите доступ и напишите адреса и индексы, которые, как вы уверены, принадлежат вам. Ошибки памяти отличаются от утечек; они часто просто IndexOutOfBoundsException
проблемы с типом.
Не открывайте и не пишите в память после освобождения.
Иногда ваши утечки / ошибки могут быть связаны друг с другом, подобно тому, как IDE обнаруживает, что вы еще не ввели закрывающую скобку. Решение одной проблемы может решить другие, поэтому найдите такую, которая выглядит хорошим виновником, и примените некоторые из этих идей:
Перечислите функции в вашем коде, которые зависят от / зависят от «нарушающего» кода, который имеет ошибку памяти. Следите за выполнением программы (возможно, даже 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)
Как помощник преподавателя, я часто видел эту ошибку. Студент использует локальную переменную и забывает обновить исходный указатель. Ошибка здесь замечает, что reallocфактически может переместить выделенную память куда-нибудь еще и изменить местоположение указателя. Затем мы уходим, resizeArrayне сообщая,
array->dataкуда был перемещен массив.
Неверная запись
1 errors in context 1 of 1:Invalid write of size 1
at 0x4005CA: main (main.c:10)Address0x51f905a 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);return0;}
Обратите внимание, что Valgrind указывает нам на закомментированную строку кода выше. Массив размером 26 индексируется [0,25], поэтому *(alphabet + 26)является недопустимой записью - это выходит за пределы. Недопустимая запись является распространенным результатом ошибок «один за другим». Посмотрите на левую сторону вашей операции присваивания.
Неверное чтение
1 errors in context 1 of 1:Invalid read of size 1
at 0x400602: main (main.c:9)Address0x51f90ba 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);return0;}
Valgrind указывает нам на прокомментированную строку выше. Посмотрите на последнюю итерацию здесь, которая есть *(destination + 26) = *(source + 26);. Тем не менее, *(source + 26)снова выходит за пределы, так же, как и недопустимая запись. Недопустимые чтения также являются частым результатом ошибочных ошибок. Посмотрите на правую сторону вашей операции присваивания.
Топия с открытым исходным кодом (U / Dys)
Как я узнаю, когда утечка моя? Как мне найти утечку, когда я использую чужой код? Я нашел утечку, которая не моя; я должен что-то сделать? Все законные вопросы. Во-первых, 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 pointerjson_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?return0;}
Это простая программа: она читает строку JSON и анализирует ее. При создании мы используем библиотечные вызовы, чтобы выполнить анализ для нас. Янссон динамически распределяет необходимые распределения, поскольку JSON может содержать собственные вложенные структуры. Однако это не означает, что мы decrefили «освобождаем» память, данную нам от каждой функции. На самом деле, этот код, который я написал выше, выбрасывает «Неверное чтение» и «Неверное чтение». Эти ошибки исчезают, когда вы убираете decrefстроку для value.
Зачем? Переменная valueсчитается «заимствованной ссылкой» в API Jansson. Янссон следит за своей памятью для вас, и вам просто нужно, чтобы decref
структуры JSON были независимы друг от друга. Урок здесь:
прочитайте документацию . В самом деле. Иногда это трудно понять, но они говорят вам, почему это происходит. Вместо этого у нас есть
существующие вопросы об этой ошибке памяти.
Что не так с этим кодом ? Это постоянно пропускает ~ 212 КиБ памяти для меня. Найдите минутку, чтобы подумать об этом. Мы включаем SDL и затем выключаем. Ответ? Нет ничего плохого.
Поначалу это может показаться странным . По правде говоря, графика грязная, и иногда вы должны принять некоторые утечки как часть стандартной библиотеки. Урок здесь: вам не нужно подавлять каждую утечку памяти . Иногда вам просто нужно подавить утечки, потому что это известные проблемы, с которыми вы ничего не можете сделать . (Это не мое разрешение игнорировать ваши собственные утечки!)
Ответы в пустоту
Как я узнаю, когда утечка моя?
Это. (99% уверен, в любом случае)
Как мне найти утечку, когда я использую чужой код?
Скорее всего, кто-то другой уже нашел это. Попробуйте Google! Если это не поможет, используйте навыки, которые я дал вам выше. Если это не помогло, и вы в основном видите вызовы API и немного собственной трассировки стека, см. Следующий вопрос.
Я нашел утечку, которая не моя; я должен что-то сделать?
Да! У большинства API есть способы сообщать об ошибках и проблемах. Используй их! Помогите вернуть инструменты, которые вы используете в своем проекте!
Дальнейшее чтение
Спасибо, что остался со мной так долго. Я надеюсь, что вы чему-то научились, так как я пытался склониться к широкому кругу людей, приходящих к этому ответу. Надеюсь, вы спросили кое-что еще: как работает распределитель памяти в C? Что такое утечка памяти и ошибка памяти? Чем они отличаются от сегфо? Как работает Valgrind? Если у вас есть что-то из этого, пожалуйста, подпитывайте свое любопытство:
Гораздо лучший ответ, позор, это не принятый ответ.
Смоляк А.
Я полагаю, что это хорошая практика, я делал это сам
А. Смоляк,
1
Могу ли я отметить этот ответ и использовать его в качестве справочной информации для себя? Хорошая работа!
Зап
это memcheckинструмент включен по умолчанию?
abhiarora
@abhiarora Да. Страница man говорит нам, что memcheckэто инструмент по умолчанию:--tool=<toolname> [default: memcheck]
Джошуа Детвилер
146
Попробуй это:
valgrind --leak-check=full -v ./your_program
Пока установлен valgrind, он будет проходить через вашу программу и сообщать вам, что не так. Это может дать вам указатели и приблизительные места, где ваши утечки могут быть найдены. Если вы segfault'ing, попробуйте запустить его gdb.
Ответы:
Как запустить Вальгринд
Не для того, чтобы оскорблять ОП, но для тех, кто пришел к этому вопросу и все еще не знаком с Linux - вам, возможно, придется установить Valgrind в вашей системе.
Valgrind легко использовать для кода C / C ++, но при правильной настройке его можно использовать и для других языков (см. Это для Python).
Чтобы запустить Valgrind , передайте исполняемый файл в качестве аргумента (вместе с любыми параметрами в программу).
Короче говоря, флаги:
--leak-check=full
: "каждая отдельная утечка будет показана подробно"--show-leak-kinds=all
: Показать все «определенные, косвенные, возможные, достижимые» виды утечек в «полном» отчете.--track-origins=yes
: Воспользуйтесь полезным выводом на скорости. Это отслеживает происхождение неинициализированных значений, которые могут быть очень полезны для ошибок памяти. Подумайте об отключении, если Valgrind неприемлемо медленен.--verbose
: Может рассказать вам о необычном поведении вашей программы. Повторите для большего многословия.--log-file
: Запись в файл Полезно, когда вывод превышает пространство терминала.Наконец, вы хотели бы увидеть отчет Valgrind, который выглядит следующим образом:
У меня течь, но ГДЕ ?
Итак, у вас утечка памяти, и Вальгринд не говорит ничего значимого. Возможно, что-то вроде этого:
Давайте посмотрим на код C, который я тоже написал:
Ну, было потеряно 5 байтов. Как это произошло? Сообщение об ошибке просто говорит
main
иmalloc
. В более крупной программе это было бы очень сложно выследить. Это из-за того, как исполняемый файл был скомпилирован . На самом деле мы можем получить построчную информацию о том, что пошло не так. Перекомпилируйте вашу программу с флагом отладки (я используюgcc
здесь):Теперь с этой отладочной сборкой Valgrind указывает на точную строку кода, выделяющую утечку памяти! (Формулировка важна: это может быть не совсем то, где находится ваша утечка, а то , что просочилось. След поможет вам найти, где .)
Методы отладки утечек памяти и ошибок
IndexOutOfBoundsException
проблемы с типом.Иногда ваши утечки / ошибки могут быть связаны друг с другом, подобно тому, как IDE обнаруживает, что вы еще не ввели закрывающую скобку. Решение одной проблемы может решить другие, поэтому найдите такую, которая выглядит хорошим виновником, и примените некоторые из этих идей:
gdb
возможно) и ищите ошибки предусловия / постусловия. Идея состоит в том, чтобы отслеживать выполнение вашей программы, сосредотачиваясь на времени жизни выделенной памяти.Взгляд на общие утечки и ошибки
Следите за своими указателями
И код:
Как помощник преподавателя, я часто видел эту ошибку. Студент использует локальную переменную и забывает обновить исходный указатель. Ошибка здесь замечает, что
realloc
фактически может переместить выделенную память куда-нибудь еще и изменить местоположение указателя. Затем мы уходим,resizeArray
не сообщая,array->data
куда был перемещен массив.Неверная запись
И код:
Обратите внимание, что Valgrind указывает нам на закомментированную строку кода выше. Массив размером 26 индексируется [0,25], поэтому
*(alphabet + 26)
является недопустимой записью - это выходит за пределы. Недопустимая запись является распространенным результатом ошибок «один за другим». Посмотрите на левую сторону вашей операции присваивания.Неверное чтение
И код:
Valgrind указывает нам на прокомментированную строку выше. Посмотрите на последнюю итерацию здесь, которая есть
*(destination + 26) = *(source + 26);
. Тем не менее,*(source + 26)
снова выходит за пределы, так же, как и недопустимая запись. Недопустимые чтения также являются частым результатом ошибочных ошибок. Посмотрите на правую сторону вашей операции присваивания.Топия с открытым исходным кодом (U / Dys)
Как я узнаю, когда утечка моя? Как мне найти утечку, когда я использую чужой код? Я нашел утечку, которая не моя; я должен что-то сделать? Все законные вопросы. Во-первых, 2 реальных примера, которые показывают 2 класса общих встреч.
Янссон : библиотека JSON
Это простая программа: она читает строку JSON и анализирует ее. При создании мы используем библиотечные вызовы, чтобы выполнить анализ для нас. Янссон динамически распределяет необходимые распределения, поскольку JSON может содержать собственные вложенные структуры. Однако это не означает, что мы
decref
или «освобождаем» память, данную нам от каждой функции. На самом деле, этот код, который я написал выше, выбрасывает «Неверное чтение» и «Неверное чтение». Эти ошибки исчезают, когда вы убираетеdecref
строку дляvalue
.Зачем? Переменная
value
считается «заимствованной ссылкой» в API Jansson. Янссон следит за своей памятью для вас, и вам просто нужно, чтобыdecref
структуры JSON были независимы друг от друга. Урок здесь: прочитайте документацию . В самом деле. Иногда это трудно понять, но они говорят вам, почему это происходит. Вместо этого у нас есть существующие вопросы об этой ошибке памяти.SDL : библиотека графики и игр
Что не так с этим кодом ? Это постоянно пропускает ~ 212 КиБ памяти для меня. Найдите минутку, чтобы подумать об этом. Мы включаем SDL и затем выключаем. Ответ? Нет ничего плохого.
Поначалу это может показаться странным . По правде говоря, графика грязная, и иногда вы должны принять некоторые утечки как часть стандартной библиотеки. Урок здесь: вам не нужно подавлять каждую утечку памяти . Иногда вам просто нужно подавить утечки, потому что это известные проблемы, с которыми вы ничего не можете сделать . (Это не мое разрешение игнорировать ваши собственные утечки!)
Ответы в пустоту
Как я узнаю, когда утечка моя?
Это. (99% уверен, в любом случае)
Как мне найти утечку, когда я использую чужой код?
Скорее всего, кто-то другой уже нашел это. Попробуйте Google! Если это не поможет, используйте навыки, которые я дал вам выше. Если это не помогло, и вы в основном видите вызовы API и немного собственной трассировки стека, см. Следующий вопрос.
Я нашел утечку, которая не моя; я должен что-то сделать?
Да! У большинства API есть способы сообщать об ошибках и проблемах. Используй их! Помогите вернуть инструменты, которые вы используете в своем проекте!
Дальнейшее чтение
Спасибо, что остался со мной так долго. Я надеюсь, что вы чему-то научились, так как я пытался склониться к широкому кругу людей, приходящих к этому ответу. Надеюсь, вы спросили кое-что еще: как работает распределитель памяти в C? Что такое утечка памяти и ошибка памяти? Чем они отличаются от сегфо? Как работает Valgrind? Если у вас есть что-то из этого, пожалуйста, подпитывайте свое любопытство:
malloc
распределителе памяти Cисточник
memcheck
инструмент включен по умолчанию?memcheck
это инструмент по умолчанию:--tool=<toolname> [default: memcheck]
Попробуй это:
valgrind --leak-check=full -v ./your_program
Пока установлен valgrind, он будет проходить через вашу программу и сообщать вам, что не так. Это может дать вам указатели и приблизительные места, где ваши утечки могут быть найдены. Если вы segfault'ing, попробуйте запустить его
gdb
.источник
your_program
== имя исполняемого файла или любую другую команду, которую вы используете для запуска приложения.Вы можете запустить:
источник
Вы можете создать псевдоним в файле .bashrc следующим образом
Поэтому, когда вы хотите проверить утечки памяти, просто
Это создаст файл журнала Valgrind в текущем каталоге.
источник