Каковы лучшие методы обнаружения утечек памяти в неуправляемом коде C / C ++? И рекомендаций по кодированию, которых следует избегать? (Как будто это так просто;)
Раньше мы использовали немного глупый способ: приращение счетчика для каждого вызова выделения памяти и уменьшение при освобождении. В конце программы значение счетчика должно быть нулевым.
Я знаю, что это не лучший способ и есть несколько уловок. (Например, если вы освобождаете память, которая была выделена вызовом API платформы, ваш счетчик выделения не будет точно соответствовать вашему счетчику освобождения. Конечно, тогда мы увеличили счетчик при вызове вызовов API, которые выделяли память.)
Я жду вашего опыта, предложений и, возможно, некоторых ссылок на инструменты, которые упростят это.
источник
Ответы:
Если ваш код C / C ++ переносим на * nix, лучше всего будет Valgrind .
источник
Если вы используете Visual Studio, Microsoft предоставляет несколько полезных функций для обнаружения и отладки утечек памяти.
Я бы начал с этой статьи: https://msdn.microsoft.com/en-us/library/x98tx3cf(v=vs.140).aspx
Вот краткое изложение этих статей. Сначала включите эти заголовки:
Затем вам нужно вызвать это, когда ваша программа завершится:
В качестве альтернативы, если ваша программа не выходит каждый раз в одном и том же месте, вы можете вызвать это в начале своей программы:
Теперь, когда программа завершает работу, все выделения, которые не были освобождены, будут напечатаны в окне вывода вместе с файлом, в котором они были выделены, и возникновением выделения.
Эта стратегия работает для большинства программ. Однако в некоторых случаях это становится трудным или невозможным. Использование сторонних библиотек, которые выполняют некоторую инициализацию при запуске, может вызвать появление других объектов в дампе памяти и затруднить отслеживание ваших утечек. Кроме того, если какой-либо из ваших классов имеет члены с тем же именем, что и любая из процедур выделения памяти (например, malloc), макросы отладки CRT вызовут проблемы.
Существуют и другие методы, описанные в упомянутой выше ссылке MSDN, которые также можно использовать.
источник
В C ++: используйте RAII. Интеллектуальные указатели нравится
std::unique_ptr
,std::shared_ptr
,std::weak_ptr
являются вашими друзьями.источник
Как разработчик C ++ вот несколько простых рекомендаций:
Что касается обнаружения утечек памяти лично, я всегда использовал Visual Leak Detector и считаю его очень полезным.
источник
Я использую DevStudio уже слишком много лет, и меня всегда удивляет, сколько программистов не знают об инструментах анализа памяти, доступных в библиотеках времени выполнения отладки. Вот несколько ссылок, с которых можно начать:
Отслеживание запросов на выделение кучи - в частности, раздел об уникальных номерах запросов на выделение
_CrtSetDbgFlag
_CrtSetBreakAlloc
Конечно, если вы не используете DevStudio, это не будет особенно полезно.
источник
Я удивлен, что никто не упомянул DebugDiag для ОС Windows.
Он работает на сборках релизов и даже на сайте заказчика.
(Вам просто нужно сохранить PDB версии выпуска и настроить DebugDiag для использования общедоступного сервера символов Microsoft)
источник
Visual Leak Detector - очень хороший инструмент, хотя он не поддерживает вызовы среды выполнения VC9 (например, MSVCR90D.DLL).
источник
Microsoft VC ++ в режиме отладки показывает утечки памяти, но не показывает, где находятся ваши утечки.
Если вы используете C ++ , вы всегда можете избежать использования нового явно: у вас есть
vector
,string
,auto_ptr
(предварительно C ++ 11, замененunique_ptr
на C ++ 11),unique_ptr
(C ++ 11) иshared_ptr
(C ++ 11) в вашем арсенале.Когда нового невозможно избежать, попробуйте скрыть его в конструкторе (и скрыть удаление в деструкторе); то же самое работает для сторонних API.
источник
Существуют различные замещающие библиотеки "malloc", которые позволят вам вызвать функцию в конце, и она расскажет вам обо всей неиспользованной памяти и, во многих случаях, о том, кто ее создал (или обновил) в первую очередь. ,
источник
Если вы используете MS VC ++, я настоятельно рекомендую этот бесплатный инструмент из codeproject: leakfinder от Йохена Калмбаха.
Вы просто добавляете класс в свой проект и вызываете
до и после кода, который вы хотите проверить на утечки.
После сборки и запуска кода Jochen предоставляет удобный инструмент с графическим интерфейсом, с помощью которого вы можете загрузить полученный файл .xmlleaks и перемещаться по стеку вызовов, в котором была сгенерирована каждая утечка, для поиска ошибочной строки кода.
PurifyPlus от Rational (ныне принадлежащий IBM) иллюстрирует утечки аналогичным образом, но я считаю, что инструмент Leakfinder действительно проще в использовании, плюс он не стоит несколько тысяч долларов!
источник
Сам никогда не использовал, но мои друзья C говорят мне Purify .
источник
Если вы используете Visual Studio, возможно, стоит взглянуть на Bounds Checker . Это не бесплатно, но было невероятно полезно для поиска утечек в моем коде. Это происходит не только с утечками памяти, но и с утечками ресурсов GDI, ошибками использования WinAPI и прочим. Он даже покажет вам, где была инициализирована утечка памяти, что значительно упростит отслеживание утечки.
источник
Я думаю, что на этот вопрос нет простого ответа. Как вы действительно можете подойти к этому решению, зависит от ваших требований. Вам нужно кроссплатформенное решение? Вы используете new / delete или malloc / free (или оба)? Вы действительно ищете только «утечки» или вам нужна лучшая защита, например обнаружение переполнения (или опустошения) буфера?
Если вы работаете на стороне Windows, библиотеки времени выполнения отладки MS имеют некоторые базовые функции обнаружения отладки, и, как уже указывал другой, есть несколько оболочек, которые могут быть включены в ваш источник, чтобы помочь с обнаружением утечек. Поиск пакета, который может работать как с new / delete, так и с malloc / free, дает вам больше гибкости.
Я недостаточно знаю о стороне Unix, чтобы оказать помощь, хотя, опять же, другие знают.
Но помимо обнаружения утечек, существует понятие обнаружения повреждения памяти через переполнение (или опустошение) буфера. Я думаю, что этот тип отладки сложнее, чем простое обнаружение утечек. Этот тип системы также усложняется, если вы работаете с объектами C ++, потому что полиморфные классы могут быть удалены различными способами, что затрудняет определение истинного базового указателя, который удаляется. Я не знаю хорошей «бесплатной» системы, которая бы обеспечивала достойную защиту от переполнения. мы написали систему (кроссплатформенную) и обнаружили, что это довольно сложно.
источник
Я хотел бы предложить кое-что, что я использовал в прошлом: элементарную программу проверки утечек, которая является довольно автоматической на уровне исходного кода. Я отдаю это по трем причинам:
Вы можете найти это полезным.
Хотя это немного круфно, я не позволяю этому смущать меня.
Несмотря на то, что он привязан к некоторым перехватчикам win32, это легко исправить.
Есть вещи, с которыми вы должны быть осторожны при его использовании: не делайте ничего, на что нужно опираться
new
в базовом коде, остерегайтесь предупреждений о случаях, которые он может пропустить в верхней части leakcheck.cpp, поймите, что если вы включите в коде, который выполняет дампы изображений (и исправляет любые проблемы), вы можете создать огромный файл.Дизайн предназначен для того, чтобы вы могли включать и выключать средство проверки без перекомпиляции всего, что включает его заголовок. Включите файл leakcheck.h, где вы хотите отслеживать проверку и один раз перестроить. После этого скомпилируйте leakcheck.cpp с LEAKCHECK #define'd или без него, а затем повторно подключите его, чтобы включить и выключить. Включение unleakcheck.h отключит его локально в файле. Предусмотрены два макроса: CLEARALLOCINFO () позволит избежать некорректного сообщения одного и того же файла и строки, когда вы просматриваете выделенный код, который не включал leakcheck.h. ALLOCFENCE () просто отбрасывает строку в сгенерированном отчете без выделения памяти.
Опять же, пожалуйста, поймите, что я не использовал это некоторое время, и вам, возможно, придется немного поработать с этим. Я добавляю это, чтобы проиллюстрировать идею. Если окажется, что интерес будет достаточным, я был бы готов разработать пример, обновив код в процессе и заменив содержимое следующего URL-адреса чем-то более приятным, что включает в себя список с прилично окрашенным синтаксисом.
Вы можете найти его здесь: http://www.cse.ucsd.edu/~tkammeye/leakcheck.html
источник
Для Linux: попробуйте Google Perftools
Есть много инструментов, которые делают аналогичный подсчет распределения / свободного места, плюсы Goolge Perftools:
источник
Лучшая защита от утечек - это структура программы, которая сводит к минимуму использование malloc. Это не только хорошо с точки зрения программирования, но также повышает производительность и удобство обслуживания. Я не говорю об использовании других вещей вместо malloc, но с точки зрения повторного использования объектов и сохранения очень явных вкладок для всех передаваемых объектов, а не распределения волей-неволей, как это часто бывает в языках со сборщиками мусора как Java.
Например, программа, над которой я работаю, имеет набор объектов кадра, представляющих данные изображения. Каждый объект фрейма имеет подчиненные данные, которые освобождает деструктор фрейма. Программа хранит список всех выделенных фреймов и, когда ей нужен новый, проверяет список неиспользуемых фреймов, чтобы увидеть, может ли она повторно использовать существующий, а не выделять новый. При выключении он просто просматривает список, освобождая все.
источник
Я бы рекомендовал использовать Memory Validator из программы проверки. Этот инструмент оказался неоценимым помощником в отслеживании утечек памяти и улучшении управления памятью приложений, над которыми я работаю.
Очень полный и быстрый инструмент.
источник
Вы подсчитываете выделение и освобождение, интерполируя свои собственные функции системных вызовов, которые записывают вызовы, а затем передают вызов реальной функции?
Это единственный способ отслеживать вызовы, исходящие от кода, который вы не написали.
Взгляните на страницу руководства ld.so. Или ld.so.1 в некоторых системах.
Также сделайте Google LD_PRELOAD, и вы найдете несколько интересных статей, объясняющих эту технику, на www.itworld.com.
источник
По крайней мере, для MS VC ++ библиотека C Runtime имеет несколько функций, которые я считал полезными в прошлом. Обратитесь к справке MSDN о
_Crt*
функциях.источник
Mmgr Пола Неттла - мой давний любимый инструмент. Вы включаете mmgr.h в свои исходные файлы, определяете TEST_MEMORY, и он доставляет текстовый файл, полный проблем с памятью, возникших во время выполнения вашего приложения.
источник
Общие правила кодирования:
источник
Инструменты отладки памяти на вес золота, но с годами я обнаружил, что можно использовать две простые идеи, чтобы предотвратить кодирование большинства утечек памяти / ресурсов.
Напишите код выпуска сразу после написания кода приобретения для ресурсов, которые вы хотите выделить. С помощью этого метода его труднее «забыть» и в некотором смысле заставляет серьезно задуматься о жизненном цикле ресурсов, используемых заранее, а не как побочные.
Используйте возврат как можно реже. То, что выделено, по возможности следует освобождать только в одном месте. Условный путь между получением ресурса и выпуском должен быть как можно более простым и очевидным.
источник
Вверху этого списка (когда я его читал) был valgrind. Valgrind отлично подходит, если вы можете воспроизвести утечку на тестовой системе. Я использовал его с большим успехом.
Что, если вы только что заметили, что производственная система сейчас протекает, и вы не знаете, как воспроизвести ее в тесте? Некоторые доказательства того, что не так, фиксируются в состоянии этой производственной системы, и этого может быть достаточно, чтобы понять, в чем проблема, чтобы вы могли ее воспроизвести.
Вот где на сцену выходит отбор проб Монте-Карло. Прочтите статью в блоге Раймонда Чена «Способ выявления утечек памяти для бедняков», а затем ознакомьтесь с моей реализацией (предполагается, что Linux, протестирован только на x86 и x86-64)
http://github.com/tialaramex/leakdice/tree/master
источник
Работая в операционной системе сотовых телефонов Motorola, мы взяли библиотеку распределения памяти, чтобы наблюдать за всем распределением памяти. Помогло найти много проблем с выделением памяти. Поскольку профилактика лучше лечения, я бы рекомендовал использовать инструмент статического анализа, такой как Klockwork или PC-Lint.
источник
lint
. Он имеет много проверок, специфичных для C ++, чего нет в afaik splint. См. Ссылку в ответе (который я переименовал с Lint в PC-Lint).Valgrind - хороший вариант для Linux. В MacOS X вы можете включить библиотеку MallocDebug, которая имеет несколько опций для отладки проблем с выделением памяти (см. Справочную страницу malloc, соответствующие подробности есть в разделе «ОКРУЖЕНИЕ»). OS X SDK также включает инструмент под названием MallocDebug (обычно устанавливается в / Developer / Applications / Performance Tools /), который может помочь вам отслеживать использование и утечки.
источник
Обнаружение:
Отладка CRT
Избегайте:
Умные указатели, Boehm GC
источник
Хорошая замена malloc, calloc и reallloc - это rmdebug, она довольно проста в использовании. Это намного быстрее, чем valgrind, поэтому вы можете тщательно протестировать свой код. Конечно, у него есть свои недостатки: как только вы обнаружите утечку, вам, вероятно, все равно придется использовать valgrind, чтобы найти, где возникает утечка, и вы можете тестировать только те маллоки, которые вы делаете напрямую. Если утечка библиотеки происходит из-за того, что вы ее неправильно используете, rmdebug ее не найдет.
http://www.hexco.de/rmdebug/
источник
Большинство профилировщиков памяти замедляют работу моего большого сложного приложения Windows до такой степени, что результаты становятся бесполезными. Есть один инструмент, который хорошо работает для поиска утечек в моем приложении: UMDH - http://msdn.microsoft.com/en-us/library/ff560206%28VS.85%29.aspx
источник
Mtrace кажется стандартным встроенным для Linux. Шаги следующие:
MALLOC_TRACE = / tmp / mtrace.dat
export MALLOC_TRACE;
mtrace your_prog_exe_name /tmp/mtrace.dat
( сначала мне пришлось установить perl-скрипт mtrace в моей системе fedora с помощью yum install glibc_utils )
источник