[Powered by Google Translate] [Valgrind] [Nate Хардисон, Гарвардский университет] Это CS50, CS50.TV] Некоторые из наиболее трудных ошибок в программах C приходят от неправильного управления памятью. Есть огромное количество способов, чтобы ввернуть вещи, в том числе выделяя неправильный объем памяти, забывая при инициализации переменных, письменной форме до или после окончания буфера, и освобождение сохранить память несколько раз. Симптомы варьируются от сбои таинственно перезаписаны значениями, Часто на местах и ​​временах далеких от первоначальной ошибки. Отслеживание наблюдаемого проблемы обратно в основной первопричины может быть сложной задачей, но, к счастью, есть полезный программу под названием Valgrind что может сделать многое, чтобы помочь. Вы запускаете программу под Valgrind чтобы обширные проверки динамической памяти ассигнований и доступов. Когда Valgrind обнаруживает проблему, он дает вам немедленный, прямой информации, которая позволяет легче найти и исправить ошибку. Valgrind также сообщения о менее опасны проблем с памятью, таких как утечки памяти, выделение динамической памяти, и забыть, чтобы освободить его. Нравится наш компилятор, Clang, на наш отладчик, GDB, Valgrind является свободным программным обеспечением, и она установлена ​​на прибор. Valgrind работает на вашем исполняемый файл, не ваш. или с. ч. файлов исходного кода, так что вы собрали последнюю дату копии вашей программы использованием Clang или сделать. Затем запустить программу под Valgrind может быть так прост, как только префикс стандартной команды программы со словом Valgrind, который запускает Valgrind и запускает программу внутри него. При запуске Valgrind делает некоторые сложные перетасовывают настроить исполняемый файл для проверки памяти, так что это может занять немного, чтобы встать и бежать. Программа будет выполнять нормально, будь то гораздо медленнее, и когда он закончится, Valgrind будет печатать отчет о своей памяти. Если все пойдет хорошо, то она будет выглядеть примерно так: В этом случае,. / Clean_program это путь к программе, я хочу бежать. И хотя это не принимать никаких аргументов, если это так я бы просто трека их на конце команды, как обычно. Чистый программа просто глупая маленькая программа, которую я создал что выделяет место для блока целыми в куче, поставить некоторые значения в них, и освобождает весь блок. Это то, что вы снимаете для, без ошибок и без утечек. Другим важным показателем является общее количество байт выделяется. В зависимости от программы, если ассигнования в мегабайтах или выше, Вы, вероятно, делаете что-то неправильно. Вы излишне хранения дубликатов? Используете ли вы кучу для хранения, когда это было бы лучше использовать стек? Таким образом, ошибки памяти может быть по-настоящему зло. Более откровенные из них вызывают захватывающие аварии, но даже тогда она может быть трудно определить что именно привело к аварии. Более коварно, программа с памятью ошибки все еще может скомпилировано и все еще может казаться правильной работы потому что вам удалось поймать удачу большую часть времени. После нескольких "успешных результатов" Вы могли бы просто думаю, что крах счастливой случайности на компьютере, но компьютер никогда не ошибается. Запуск Valgrind может помочь вам отследить причину видимых ошибок памяти а также найти скрывающихся ошибок, которые вы даже не знали еще о. Каждый раз, когда Valgrind обнаруживает проблему, он выводит информацию о том, что он наблюдал. Каждый элемент является довольно кратким - Источник линия нарушителя инструкций, в чем дело, и немного информации о памяти участвуют - но часто это достаточно информации, чтобы обратить ваше внимание на правильное место. Вот пример из Valgrind работает на багги программы , что делает недействительным чтения динамической памяти. Мы не видим никаких ошибок или предупреждений в компиляцию. Ой-ой, ошибка Общий говорит, что есть две ошибки - два недействительным прочтений размером 4 - байт, то есть. Оба плохо читает произошла в основной функцией invalid_read.c, первым на линии 16, а второй на линии 19. Давайте посмотрим на код. Похоже, что первый вызов Printf пытается прочитать одну Int прошлом концу нашего блока памяти. Если мы оглянемся на выходе Valgrind, в мы видим, что Valgrind сказал нам именно это. Адрес мы пытаемся читать начинает 0 байт в конце прошлого блок размером 16 байта - четыре 32-разрядных целых чисел, что мы выделили. То есть, адреса мы пытались прочитать начинается в самом конце нашего блока, так же, как мы видим в наших плохих Printf вызова. Теперь, недействительными прочтений не кажется, что крупные сделки, Но если вы используете эти данные для управления потоком ваша программа - Например, как часть, если заявление или петля - Затем вещи могут молча идут плохо. Смотрите, как я могу запустить программу invalid_read и ничего необычного не происходит. Страшно, да? Теперь, давайте посмотрим на несколько видов ошибок, которые могут возникнуть в коде, и мы увидим, как Valgrind обнаруживает их. Мы только что видели пример invalid_read, так что теперь давайте посмотрим invalid_write. Опять же, никаких ошибок или предупреждений в компиляцию. Хорошо, Valgrind говорит, что есть две ошибки в этой программе - и invalid_write и invalid_read. Давайте проверим этот код. Похоже, что у нас есть экземпляр классического StrLen плюс одна ошибка. Кодекс не таНос дополнительный байт пространства для / 0 характера, поэтому, когда копия ул пошла писать на ssubstrlen "CS50 камни!" он написал 1 байт в конце прошлого нашего блока. Invalid_read приходит тогда, когда мы обращаемся к Printf. Printf заканчивается чтением недействительным памяти при чтении / 0 символов как это выглядит в конце этой струны это печать. Но все это не избежал Valgrind. Мы видим, что он пойман invalid_write как часть ул копию в строке 11 основных и invalid_read является частью Printf. Rock On, Valgrind. Опять же, это может показаться не имеет большого значения. Мы можем запустить эту программу снова и снова вне Valgrind и не вижу никакой ошибки симптомов. Тем не менее, давайте посмотрим на небольшое изменение этого, чтобы увидеть как вещи могут стать очень плохо. Так что, правда, мы злоупотребление вещей больше, чем просто немного в этом коде. Мы только выделения места в динамической памяти для двух строк Длина CS50 пород, на этот раз, помня / 0 характера. Но тогда мы бросаем в супер-длинная строка в блоке памяти что S указывает. Какой эффект будет, что есть на блок памяти, что T указывает на? Ну, если T указывает на память, что просто рядом с S, предстоящие только после этого, Затем мы могли бы написано над частью T. Давайте запустим этот код. Посмотрите, что произошло. Мы строк хранится в нашей куче блоков как представляется, надлежащим образом не печатается. Ничто, кажется, в корне ошибочна. Тем не менее, давайте вернемся в наш код и закомментируйте строку, где мы копируем CS50 пород во второй блок памяти, на который указывает тонн. Теперь, когда мы запустим этот код, мы должны Только увидеть содержимое первого блока памяти распечатать. Ух ты, даже если мы этого не сделали, ул копию любые символы, во втором блоке куча, на которую указывает T, мы получаем печать. Действительно, строка, которую мы заправленные в нашем первом блоке захватили первый блок, а во втором блоке, делает все кажется нормальным. Valgrind, однако, говорит нам правду. Там мы идем. Все эти недействительным читает и пишет. Давайте посмотрим на пример другого рода ошибки. Здесь мы делаем что-то довольно неудачно. Мы захватить пространство для Int в куче, и мы инициализируем указатель Int - P - указать на это пространство. Тем не менее, в то время как наш указатель инициализируется, данные, которые он указывает только имеет все барахло находится в той части кучи. Поэтому, когда мы загрузить данные в Int я, Мы технически инициализации я, но мы делаем это с нежелательных данных. Вызов утверждают, что это удобный макрос отладки определены в метко назвал утверждают, библиотеки, прервет программу, если ее тест условие не выполняется. То есть, если я не равно 0. В зависимости от того, что было в куче пространство, на которое указывает р, эта программа может работать иногда и не в другое время. Если это работает, мы просто повезло. Компилятор не будет ловить эту ошибку, но уверен, Valgrind воли. Там мы видим ошибки, вытекающие из нашего использования, что нежелательные данные. При выделении динамической памяти, но не освобождает его или освободить его, что называется утечка. Для небольшой, недолгой программа, которая запускается и тут же выходит, Утечки довольно безвредны, но для проектов большего размера и / или долговечность, даже небольшие утечки могут составить в нечто майора. Для CS50, мы ожидаем, что вы заботиться о освобождая все кучи памяти, которые вы выделяете, так как мы хотим, чтобы вы развивать навыки правильно обращаться с ручной процесс требуется C. Чтобы сделать это, ваша программа должна иметь точную одно-однозначное соответствие между таНос и бесплатные звонки. К счастью, Valgrind может помочь вам с утечками памяти тоже. Вот вытекающей программу под названием leak.c, что выделяет пространства в куче, пишет он, но не освободить его. Мы скомпилировать его с Марка и запустить его под Valgrind, и мы видим, что, хотя у нас нет никаких ошибок памяти, у нас есть одна утечка. Есть 16 байт определенно потерял, Это означает, что указатель на эту память не была в рамки, когда программа завершится. Теперь, Valgrind не дает нам массу информации об утечке, Но если мы будем следовать этой небольшой записке, что он дает вниз, к нижней части его доклада перезапустить с - утечка проверить = полный , чтобы увидеть полную информацию о утечка памяти, мы получим больше информации. Теперь, в кучу резюме, Valgrind говорит нам, где память, что было потеряно было первоначально выделено. Так же, как мы знаем, от поиска в исходном коде, Valgrind сообщает нам, что мы утечка памяти выделяется с призывом таНос на линии 8 из leak.c В основные функции. Довольно отличный. Valgrind классифицирует утечек с помощью этих терминов: Определенно потеряли - это динамической памяти в котором программа не имеет указателя. Valgrind знает, что ты когда-то был указатель, но с тех пор потерял его. Эта память определенно утечка. Косвенно потеряли - это динамической памяти к которой только указатели к нему также будут потеряны. Например, если вы потеряли ваш указатель на первый узел связанного списка, Затем первый узел сам бы определенно потерял, в то время как во всех узлах будет косвенно потерял. Возможно, потерял - это динамической памяти к которой Valgrind не может быть уверен, есть ли указатель или нет. Тем не менее достижимым является динамической памяти к которому программа по-прежнему имеет указатель на выходе, Обычно это означает, что глобальная переменная указывает на это. Чтобы проверить эти утечки, вы также должны включить опцию - Все еще достижима = да В вашем вызове Valgrind. Эти различные случаи могут потребоваться различные стратегии для очистки их, но утечки должны быть устранены. К сожалению, фиксируя утечки может быть трудно сделать, С неправильные вызовы бесплатно можно взорвать вашу программу. Например, если мы посмотрим на invalid_free.c, мы видим пример плохого освобождения памяти. Каким должно быть ни одного звонка, чтобы освободить весь блок памяти, на которую указывает int_block, вместо этого стала попытка освободить каждый Int размера раздела в памяти отдельно. Это катастрофически не удастся. Boom! Какие ошибки. Это, безусловно, не есть хорошо. Если вы застряли с такой ошибкой, хотя, и вы не знаете, где искать, падать обратно на ваш новый лучший друг. Вы уже догадались - Valgrind. Valgrind, как всегда, точно знает, в чем дело. Идентификатор и бесплатно рассчитывает не совпадают. Мы получили 1 идентификатор и 4 освобождает. И Valgrind также говорит нам, где первый звонок бесплатный плохо - тот, который вызвал разрушения - идет от - строка 16. Как видите, плохо звонков, чтобы освободить действительно плохи, поэтому мы рекомендуем позволяя вашей программе утечки в то время как вы работаете на получение функциональных правильно. Начните искать утечку только после того, как ваша программа работает правильно, без каких-либо других ошибок. И это все, что у нас есть для этого видео. Теперь, что же вы ждете? Перейти запустить Valgrind ваших программ прямо сейчас. Меня зовут Нейт Хардисон. Это CS50. [CS50.TV]