Основные замечания по использованию Valgrind при отладке кода C, скомпилированного с GCC:
Скомпилируйте ваш код, используя -O0. В некоторых относительно редких случаях (например, встроенная сборка) вам может понадобиться -O1. Никогда используйте более высокие уровни оптимизации. Компилятор искажает ваш код настолько, что может сделать вашу жизнь невозможной. Переменные могут полностью исчезать, функции могут загадочно уходить, когда они встроены, циклы становятся развернутыми и так далее. В принципе, с чем-либо, кроме -O0, вы рискуете, что исполняемый код будет мало похож на ваш исходный код.
Используйте опцию -g GCC для добавления отладочных символов в ваш код и НЕ удаляйте исполняемые файлы. Как и любой другой отладчик, valgrind будет генерировать бесконечно более полезный вывод с доступными символами отладки. Они помогут valgrind сопоставить адреса памяти с конкретными файлами и номерами строк в вашем коде, что неоценимо.
Для отслеживания утечек памяти и многих других проблем я предлагаю запустить вашу программу с:
valgrind --log-file=valgrind.log --leak-check=full --track-origins=yes --show-reachable=yes ./program
Затем найдите файл valgrind.log на предмет найденных проблем.
EDIT:
Об опциях valgrind, которые я предложил:
- log-file = говорит valgrind отправлять свои выходные данные в файл, что, как я полагаю, может упростить задачу при отладке программ с выводом на консоль или при обнаружении множества проблем.
- проверка на утечку = полная команда сообщает valgrind подробности о каждом утечке блока памяти.
- track-originins = yes сообщает valgrind, откуда получены неинициализированные значения. Он не имеет ничего общего с утечками памяти, хотя может помочь справиться с другими проблемами. Однако это замедляет работу вашей программы, поэтому вы можете удалить эту опцию и добавлять ее только при отслеживании неинициализированных значений.
- show-reachable = yes указывает valgrind выводить блоки памяти, которые были выделены и не освобождены, даже если на выходе из программы все еще есть указатели. Эти блоки не являются технически потерянными / утечками, поскольку у вас все еще есть указатели на них. Тем не менее, они могут а) указать на проблему с логикой в вашей программе (например, список, который растет бесконечно) б) они могут и станут утечками памяти, если ваш main () станет интегрированным как функция в другой более крупной программе. Было бы лучше, если бы таких проблем не осталось.
Существует опция --track-fds = yes, которая может помочь найти утечку файловых дескрипторов вместо просто памяти.
Некоторые программисты выступают против освобождения памяти или закрытия файловых дескрипторов в конце программы, так как в любом случае ОС делает это. Хотя - это преимущество в производительности и размере кода, IMHO, это должно быть сделано только опытными программистами, и это должно быть сделано путем удаления указанного кода для производственного выпуска, а не просто никогда не пишу это. Иначе, это поощряет плохие методы кодирования, которые не должны быть разрешены.
РЕДАКТИРОВАТЬ 2:
Один важный совет: если valgrind указывает на проблему в вашем коде, это, скорее всего, правильно, даже если ваша программа не падает. Некоторые «незначительные» ошибки (например, чтение одного байта за концом буфера) могут оставаться невидимыми, в зависимости от выравнивания структуры, поведения распределителя памяти, платформы, версии и флагов компилятора или фазы луны. Код с такими проблемами может просто сломаться, если вы измените компилятор, libc, платформу или битность (например, перейдите с 64 на 32 бит).