Каковы наилучшие методы обнаружения утечек памяти в неуправляемом коде C / C++? И рекомендаций по кодированию, которых следует избегать? (Как будто это так просто;)
В прошлом мы использовали немного глупый способ: иметь приращение счетчика для каждого вызова выделения памяти и уменьшение при освобождении. В конце программы значение счетчика должно быть нулевым.
Я знаю, что это не лучший способ и есть несколько уловок. (Например, если вы освобождаете память, которая была выделена вызовом API платформы, ваш счетчик выделения не будет точно соответствовать вашему счетчику освобождения. Конечно, тогда мы увеличили счетчик при вызове вызовов API, которые выделяли память.)
Я жду вашего опыта, предложений и, возможно, некоторых ссылок на инструменты, которые упростят это.
для поиска утечек памяти проверьте здесь: theunixshell.blogspot.com/2013/11/…
Что касается предотвращения утечек, в следующем посте есть несколько советов: http://stackoverflow.com/questions/27492/c-memory-management
Я использовал это с Visual Studio для обнаружения утечки памяти. codeproject.com/KB/applications/visualleakdetector.aspx
Я задал этот вопрос здесь: http://stackoverflow.com/questions/25730/what-is-the-best-fr ee-memory-Leak-Detec tor-for-a-cc-program -and-its-plug-in-dll S и имел большой успех с Визуальный детектор утечки.
Веб-страница упала, но теперь я решил опубликовать исходный код своего инструмента - вот он: sourceforge.net/projects/diagnostic
Я не думаю, что это плохой вопрос, поскольку он не спрашивает: «Предложите инструмент для ...». Очевидно, что люди будут использовать инструменты для этого.





Сам никогда не использовал, но мои друзья C говорят мне Очистить.
Существуют различные замещающие библиотеки "malloc", которые позволят вам вызвать функцию в конце, и она расскажет вам обо всей неиспользованной памяти и, во многих случаях, о том, кто ее создал (или обновил) в первую очередь. .
Если ваш код C / C++ переносится на * nix, лучше Валгринд мало что может.
Valgrind теперь также работает с OS X, поэтому Linux - не единственный вариант.
Valgrind для Linux (и OS X). Если использовать виндовс - делекер - лучше всего!
@JordiBunster: Отлично! Но на основе времени выполнения. С большой кодовой базой (написано на C в случае необходимости) вы в основном будете тестировать свою программу на то, как она была спроектирована. Злоумышленник может потратить несколько тысяч часов на чтение кода, чтобы найти эксплойт утечки памяти. Я ожидал появления автоматизированного инструмента для анализа исходного кода, подобного тому, который существует для JavaScript.
Работая в операционной системе сотовых телефонов Motorola, мы взяли библиотеку распределения памяти, чтобы наблюдать за всем распределением памяти. Помогло найти много проблем с выделением памяти. Поскольку профилактика лучше лечения, я бы рекомендовал использовать инструмент статического анализа, такой как Klockwork или PC-Lint.
Шина - это новая замена ворса.
@ user14788: Продукт Gimpel PC-Lint намного современнее старого Unix lint. В нем есть много проверок, специфичных для C++, чего нет в afaik splint. См. Ссылку в ответе (который я переименовал с Lint в PC-Lint).
Вы подсчитываете выделение и освобождение, интерполируя свои собственные функции системных вызовов, которые записывают вызовы, а затем передают вызов реальной функции?
Это единственный способ отслеживать вызовы, исходящие от кода, который вы не написали.
Взгляните на страницу руководства для ld.so. Или ld.so.1 в некоторых системах.
Также сделайте Google LD_PRELOAD, и вы найдете несколько интересных статей, объясняющих эту технику, на www.itworld.com.
Как разработчик C++ вот несколько простых рекомендаций:
Что касается обнаружения утечек памяти лично, я всегда использовал Визуальный детектор утечки и считаю его очень полезным.
Visual Leak Detectore перемещен на новый сайт vld.codeplex.com
VLD - ДЕЙСТВИТЕЛЬНО хороший течеискатель - я полностью рекомендую его всем, кто использует VC++.
+1 за пункт №1. Это абсолютно фундаментальная вещь. К сожалению, мне кажется, что некоторые из крупнейших библиотек "C++" склонны избегать выделения стека и / или RAII в пользу Pointers Everywhere, часто без видимой причины. Таким образом, они становятся «C с классами», а не настоящим C++.
Microsoft VC++ в режиме отладки показывает утечки памяти, но не показывает, где находятся ваши утечки.
Если вы используете C++, вы всегда можете избежать использования new явно: у вас есть vector, string, auto_ptr (до C++ 11; заменен на unique_ptr в C++ 11), unique_ptr (C++ 11) и shared_ptr (C++ 11) в вашем арсенале.
Когда нового невозможно избежать, попробуйте скрыть его в конструкторе (и скрыть удаление в деструкторе); то же самое работает для сторонних API.
и не забывайте правило 3 или 5, тогда
Если вы используете Visual Studio, возможно, стоит взглянуть на Проверка границ. Это не бесплатно, но очень помогло в поиске утечек в моем коде. Это происходит не только с утечками памяти, но и с утечками ресурсов GDI, ошибками использования WinAPI и прочим. Он даже покажет вам, где была инициализирована утечка памяти, что значительно упростит отслеживание утечки.
Если вы используете MS VC++, я настоятельно рекомендую этот бесплатный инструмент из codeproject: поисковик, автор - Йохен Кальмбах.
Вы просто добавляете класс в свой проект и вызываете
InitAllocCheck(ACOutput_XML)
DeInitAllocCheck()
до и после кода, который вы хотите проверить на утечки.
После сборки и запуска кода Jochen предоставляет удобный инструмент с графическим интерфейсом, с помощью которого вы можете загрузить полученный файл .xmlleaks и перемещаться по стеку вызовов, в котором была сгенерирована каждая утечка, для поиска ошибочной строки кода.
PurifyPlus от Rational (ныне принадлежащий IBM) иллюстрирует утечки аналогичным образом, но я считаю, что инструмент Leakfinder действительно проще в использовании, причем бонус в том, что он не стоит несколько тысяч долларов!
Я проверил утечку, и он выглядит нормально, но к вашему сведению, он не будет работать как есть для x64, потому что он содержит встроенную сборку.
Я использую DevStudio уже слишком много лет, и меня всегда поражает, сколько программистов не знают об инструментах анализа памяти, доступных в библиотеках времени выполнения отладки. Вот несколько ссылок, с которых можно начать:
Отслеживание запросов на выделение кучи - в частности, раздел об уникальных номерах запросов на выделение
Конечно, если вы не используете DevStudio, это не принесет особой пользы.
По крайней мере, для MS VC++ библиотека C Runtime имеет несколько функций, которые я считал полезными в прошлом. Обратитесь к справке MSDN о функциях _Crt*.
В C++: используйте RAII. Умные указатели вроде std::unique_ptr, std::shared_ptr, std::weak_ptr - ваши друзья.
а std: vector - отличная замена, когда массивы (буферы) освобождаются в той же функции, в которой они выделяются.
По крайней мере, std :: auto_ptr и boost :: shared_ptr все еще подвержены утечкам.
Только если вы используете их неправильно, хотя я должен признать, что для std :: auto_ptr неправильно использовать его довольно просто.
Хотя это хороший совет для стандартов кодирования, он не дает ответа на вопрос. Даже использование shared_ptr может привести к утечкам с круговыми зависимостями. И у вас могут быть «утечки» с неограниченными стратегиями кэширования, которые применимы даже к языкам со сборкой мусора.
@CashCow: вы правы. Хотя я еще не видел этого на практике, вероятно, потому, что я использую их экономно. Процитируем ответ ниже: «Используйте указатели только в случае крайней необходимости».
Valgrind - хороший вариант для Linux. В MacOS X вы можете включить библиотеку MallocDebug, в которой есть несколько опций для отладки проблем с распределением памяти (см. Справочную страницу malloc, в разделе «ОКРУЖЕНИЕ» есть соответствующие детали). OS X SDK также включает инструмент под названием MallocDebug (обычно устанавливается в / Developer / Applications / Performance Tools /), который может помочь вам отслеживать использование и утечки.
Я думаю, что на этот вопрос нет простого ответа. Как вы действительно можете подойти к этому решению, зависит от ваших требований. Вам нужно кроссплатформенное решение? Вы используете 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
Обнаружить:
Отладка CRT
Избегать:
Умные указатели, Boehm GC
Если вы используете Visual Studio, Microsoft предоставляет несколько полезных функций для обнаружения и отладки утечек памяти.
Я бы начал с этой статьи: https://msdn.microsoft.com/en-us/library/x98tx3cf(v=vs.140).aspx
Вот краткое изложение этих статей. Сначала включите эти заголовки:
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
Затем вам нужно вызвать это при выходе из вашей программы:
_CrtDumpMemoryLeaks();
В качестве альтернативы, если ваша программа не выходит каждый раз в одном и том же месте, вы можете вызвать это в начале своей программы:
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
Теперь, когда программа завершает работу, все выделения, которые не были освобождены, будут напечатаны в окне вывода вместе с файлом, в котором они были выделены, и вхождением выделения.
Эта стратегия работает для большинства программ. Однако в некоторых случаях это становится трудным или невозможным. Использование сторонних библиотек, которые выполняют некоторую инициализацию при запуске, может вызвать появление других объектов в дампе памяти и затруднить отслеживание ваших утечек. Кроме того, если какой-либо из ваших классов имеет члены с тем же именем, что и любая из подпрограмм распределения памяти (например, malloc), макросы отладки CRT вызовут проблемы.
Существуют и другие методы, описанные в упомянутой выше ссылке MSDN, которые также можно использовать.
Замечание об этом методе: похоже, что он работает, только если вы используете чистый C с malloc и free. Подробный отчет, который включает номера строк, не создается, если вы используете C++ new и delete.
@Zach: на самом деле вы тоже можете заставить это работать (в любом случае, для любого кода, который вы действительно компилируете) - см. Принятый ответ в social.msdn.microsoft.com/forums/en-US/vcgeneral/thread/…
Будет ли это работать и в режиме выпуска?
@ user3152463 Нет. По документации будет работать только для отладочной сборки: msdn.microsoft.com/en-us/library/e5ewb1h3(v=vs.71).aspx
Эта строка неверна: #define CRTDBG_MAP_ALLOC Это должно быть: #define _CRTDBG_MAP_ALLOC
Если вы используете C++, вы можете создать класс, который его деструктор вызывает _CrtDumpMemoryLeaks, и создать его статический экземпляр. деструктор будет вызываться при выходе из приложения
Mmgr Пола Неттла - мой давний любимый инструмент. Вы включаете mmgr.h в свои исходные файлы, определяете TEST_MEMORY, и он доставляет текстовый файл, полный проблем с памятью, возникших во время запуска вашего приложения.
Для Linux: Попробуйте Google Perftools
Есть много инструментов, которые делают аналогичный подсчет распределения / свободного места, плюсы Goolge Perftools:
перейти к: github.com/gperftools/gperftools
Общие правила кодирования:
Лучшая защита от утечек - это структура программы, которая сводит к минимуму использование malloc. Это не только хорошо с точки зрения программирования, но также повышает производительность и удобство обслуживания. Я не говорю об использовании других вещей вместо malloc, но с точки зрения повторного использования объектов и сохранения очень явных вкладок для всех передаваемых объектов, а не распределения волей-неволей, как это часто бывает в языках со сборщиками мусора как Java.
Например, программа, над которой я работаю, имеет набор объектов кадра, представляющих данные изображения. Каждый объект фрейма имеет подчиненные данные, которые освобождает деструктор фрейма. Программа ведет список всех выделенных фреймов и, когда ей нужен новый, проверяет список неиспользуемых фреймов, чтобы увидеть, может ли она повторно использовать существующий, а не выделять новый. При выключении он просто перебирает список, освобождая все.
Я бы рекомендовал использовать Валидатор памяти из программы проверки. Этот инструмент оказался неоценимым помощником в отслеживании утечек памяти и улучшении управления памятью приложений, над которыми я работаю.
Очень полный и быстрый инструмент.
Memory Validator также предоставляет имя файла и номер строки для C#, который вызывает ваш собственный код. 64-разрядная версия находится в стадии бета-тестирования
Я удивлен, что никто не упомянул DebugDiag для ОС Windows. Работает и на релизных сборках, и даже на сайте заказчика. (Вам просто нужно сохранить PDB версии выпуска и настроить DebugDiag для использования общедоступного сервера символов Microsoft)
Ссылка больше не работает, попробуйте здесь для документации: support.microsoft.com/kb/2580960 и здесь, чтобы скачать: microsoft.com/en-us/download/details.aspx?id=26798
Хорошая замена malloc, calloc и reallloc - это rmdebug, она довольно проста в использовании. Это намного быстрее, чем valgrind, поэтому вы можете тщательно протестировать свой код. Конечно, у него есть свои недостатки: как только вы обнаружите утечку, вам, вероятно, все равно придется использовать valgrind, чтобы найти место ее появления, и вы можете тестировать только те маллоки, которые вы делаете напрямую. Если утечка библиотеки происходит из-за того, что вы ее неправильно используете, rmdebug ее не найдет.
Visual Leak Detector - очень хороший инструмент, хотя он не поддерживает вызовы во время выполнения VC9 (например, MSVCR90D.DLL).
Этот инструмент действительно идеален! Это избавляет вас от необходимости использовать _CrtDumpMemoryLeaks (); и друзья, как описано в MSDN. Всего одно включение, и он все раскрывает! Работает даже в старых библиотеках C!
Новая версия (для VS2013) находится здесь: vld.codeplex.com
Mtrace кажется стандартным встроенным для Linux. Шаги следующие:
mtrace не очень полезен для C++
Инструменты отладки памяти на вес золота, но с годами я обнаружил, что можно использовать две простые идеи, чтобы предотвратить кодирование большинства утечек памяти / ресурсов.
Напишите код выпуска сразу после написания кода приобретения для ресурсов, которые вы хотите выделить. С помощью этого метода труднее «забыть» и в некотором смысле заставляет серьезно задуматься о жизненном цикле ресурсов, используемых заранее, а не как побочные.
Используйте отдачу как можно реже. То, что выделено, по возможности следует освобождать только в одном месте. Условный путь между получением ресурса и выпуском должен быть максимально простым и очевидным.
Вверху этого списка (когда я его читал) был valgrind. Valgrind отлично подходит, если вы можете воспроизвести утечку на тестовой системе. Я использовал его с большим успехом.
Что, если вы только что заметили, что производственная система сейчас протекает, и вы не знаете, как воспроизвести это в тесте? Некоторые свидетельства того, что не так, фиксируются в состоянии этой производственной системы, и этого может быть достаточно, чтобы понять, в чем проблема, чтобы вы могли ее воспроизвести.
Вот где на сцену выходит сэмплинг Монте-Карло. Прочтите статью в блоге Раймонда Чена, «Способ бедняков определять утечки памяти», а затем проверить мою реализацию (предполагается, что Linux, протестирован только на x86 и x86-64)
Большинство профилировщиков памяти замедляют работу моего большого сложного приложения Windows до такой степени, что результаты становятся бесполезными. Есть один инструмент, который хорошо работает для поиска утечек в моем приложении: UMDH - http://msdn.microsoft.com/en-us/library/ff560206%28VS.85%29.aspx
Я не понимаю, почему замедление делает результаты бесполезными. Несомненно, утечка памяти происходит независимо от скорости работы программы. Смысл этих инструментов - найти утечки, так в чем же проблема? Неужели он работал так медленно, что вы физически не могли заставить его покрыть все пути кода, чтобы профилировать их?
вы ищите valgrind (для linux) или deleaker (для windows), также смотрите визуальный детектор утечек ...