Как найти утечку памяти в коде / проекте C ++? - PullRequest
152 голосов
/ 07 июня 2011

Я программист C ++ на платформе Windows. Я использую Visual Studio 2008.

Я обычно заканчиваю в коде утечками памяти.

Обычно я проверяю код на наличие утечки памяти, но она громоздка и не всегда подходит.

Поскольку я не могу позволить себе платное средство обнаружения утечек памяти, я хотел, чтобы вы, ребята, предложили наилучшие возможные способы избежать утечек памяти.

  1. Я хочу знать, как программист может обнаружить утечки памяти.
  2. Существует ли какой-либо стандарт или процедура, которой следует следовать, чтобы убедиться в отсутствии утечки памяти в программе?

Ответы [ 17 ]

231 голосов
/ 07 декабря 2011

Инструкции

Вещи, которые вам понадобятся

  • Владение компилятором C ++
  • C ++
  • Отладчик и другиеинструменты следственного программного обеспечения

1

Понимание основ оператора.Оператор C ++ «new» выделяет кучу памяти.Оператор «delete» освобождает кучу памяти.Для каждого «нового» вы должны использовать «удалить», чтобы освободить ту же выделенную память:

char* str = new char [30]; // Allocate 30 bytes to house a string.

delete [] str; // Clear those 30 bytes and make str point nowhere.

2

Перераспределять память только в том случае, если вы удалили.В приведенном ниже коде str получает новый адрес со вторым распределением.Первый адрес безвозвратно утерян, как и 30 байтов, на которые он указывал.Теперь их невозможно освободить, и у вас есть утечка памяти:

char* str = new char [30]; // Give str a memory address.

// delete [] str; // Remove the first comment marking in this line to correct.

str = new char [60]; /* Give str another memory address with
                                                    the first one gone forever.*/

delete [] str; // This deletes the 60 bytes, not just the first 30.

3

Смотрите эти назначения указателей.Каждая динамическая переменная (выделенная память в куче) должна быть связана с указателем.Когда динамическая переменная отсоединяется от своего указателя (ей), ее становится невозможно стереть.Опять же, это приводит к утечке памяти:

char* str1 = new char [30];

char* str2 = new char [40];

strcpy(str1, "Memory leak");

str2 = str1; // Bad! Now the 40 bytes are impossible to free.

delete [] str2; // This deletes the 30 bytes.

delete [] str1; // Possible access violation. What a disaster!

4

Будьте осторожны с местными указателями.Указатель, который вы объявляете в функции, размещается в стеке, но динамическая переменная, на которую он указывает, размещается в куче.Если вы не удалите его, оно будет сохраняться после выхода из функции:

void Leak(int x){

char* p = new char [x];

// delete [] p; // Remove the first comment marking to correct.

}

5

Обратите внимание на квадратные скобки после слова «удалить».Используйте «delete» для освобождения одного объекта.Используйте «delete» [] в квадратных скобках, чтобы освободить массив кучи.Не делайте что-то вроде этого:

char* one = new char;

delete [] one; // Wrong

char* many = new char [30];

delete many; // Wrong!

6

Если утечка еще разрешена - я обычно ищу ее с помощью средства удаления (проверьте здесь: http://deleaker.com).

Спасибо!

28 голосов
/ 07 июня 2011

Вы можете использовать некоторые методы в своем коде для обнаружения утечки памяти. Самый распространенный и самый простой способ обнаружения - определить макрос, скажем, DEBUG_NEW, и использовать его вместе с предопределенными макросами, такими как __FILE__ и __LINE__, чтобы обнаружить утечку памяти в вашем коде. Эти предопределенные макросы сообщают вам номер файла и номер строки утечки памяти.

DEBUG_NEW - это просто MACRO, который обычно определяется как:

#define DEBUG_NEW new(__FILE__, __LINE__)
#define new DEBUG_NEW

Так что, где бы вы ни использовали new, он также может отслеживать файл и номер строки, которые могут быть использованы для обнаружения утечки памяти в вашей программе.

И __FILE__, __LINE__ являются предопределенными макросами , которые оценивают имя файла и номер строки соответственно, где вы их используете!

Прочитайте следующую статью, в которой очень красиво объясняется техника использования DEBUG_NEW с другими интересными макросами:

Кросс-платформенный детектор утечки памяти


Из Википедия ,

Debug_new относится к технике на C ++ перегрузить и / или переопределить оператор новый и оператор удалить, чтобы перехватить распределение памяти и вызовы освобождения, и, таким образом, отладка программа для использования памяти. Это часто включает в себя определение макроса с именем DEBUG_NEW, и делает новый стать что-то вроде нового (_ FILE _, _ LINE _) записать информацию о файле / строке на распределение. Microsoft Visual C ++ использует эта техника в своем Microsoft Базовые классы. Есть некоторые способы расширить этот метод, чтобы избежать используя переопределение макроса, пока еще возможность отображения файла / строки информация о некоторых платформах. Там Есть много присущих этому ограничений метод. Это относится только к C ++, и не может поймать утечки памяти C функционирует как malloc. Тем не менее, это может быть очень простым в использовании, а также очень быстро, если сравнивать с некоторыми другими комплексные решения для отладки памяти.

14 голосов
/ 07 июня 2011

Существуют некоторые хорошо известные методы программирования, которые помогут вам свести к минимуму риск возникновения утечек памяти из первых рук:

  • , если вам нужно выполнить собственное динамическое распределение памяти, напишите new и delete всегда попарно, и убедитесь, что код выделения / освобождения вызывается попарно
  • избегайте динамического выделения памяти, если можете.Например, используйте vector<T> t везде, где возможно вместо T* t = new T[size]
  • , используйте «умные указатели», такие как «умные указатели повышения» (http://www.boost.org/doc/libs/1_46_1/libs/smart_ptr/smart_ptr.htm)
  • мой личный фаворит: убедитесь, что вы поняли концепциювладение указателем, и убедитесь, что везде, где вы используете указатели, вы знаете, какая сущность кода является владельцем
  • узнать, какие конструкторы / операторы присваивания автоматически создаются компилятором C ++, и что это означает, если выиметь класс, которому принадлежит указатель (или что это означает, если у вас есть класс, содержащий указатель на объект, который он не владеет).
8 голосов
/ 27 сентября 2012
8 голосов
/ 07 июня 2011
  1. Скачать Средства отладки для Windows .
  2. Используйте утилиту gflags для включения трассировки стека в пользовательском режиме.
  3. Используйте UMDH, чтобы сделать несколько снимков памяти вашей программы. Сделайте снимок до того, как будет выделена память, и сделайте второй снимок после того момента, когда вы считаете, что ваша программа вытекла из памяти. Возможно, вы захотите добавить в программу паузы или подсказки, чтобы дать вам возможность запустить UMDH и сделать снимки.
  4. Запустите UMDH еще раз, на этот раз в его режиме, который делает различие между двумя снимками. Затем он сгенерирует отчет, содержащий стеки вызовов о предполагаемых утечках памяти.
  5. Восстановление прежних настроек gflags, когда вы закончите.

UMDH даст вам больше информации, чем куча отладки CRT, потому что она следит за распределением памяти по всему вашему процессу; он даже может сказать вам, если утечка компонентов сторонних производителей.

7 голосов
/ 06 июня 2016

Запуск «Valgrind» может:

1) Помочь определить утечки памяти - показать, сколько у вас утечек памяти, и указать на строки вкод, в котором была выделена утечка памяти.

2) Укажите неправильные попытки освободить память (например, неправильный вызов "delete")

Инструкции дляиспользуя "Valgrind"

1) Получите valgrind здесь .

1) Скомпилируйте свой код с флагом -g

3) В вашемshell shell:

valgrind --leak-check=yes myprog arg1 arg2

Где "myprog" - это ваша скомпилированная программа, а "arg1", "arg2" - аргументы вашей программы.

4) Результатом является список вызовов malloc /new, который не имел последующих вызовов для свободного удаления.

Например:

==4230==    at 0x1B977DD0: malloc (vg_replace_malloc.c:136)

==4230==    by 0x804990F: main (example.c:6)

Сообщает вам, в какой строке был вызван malloc (который не был освобожден).

Как указано другими, убедитесь, что для каждого «нового» / «malloc» вызова у вас есть последующий «удалить» / «бесплатный» вызов.

5 голосов
/ 07 июня 2011
  1. В visual studio имеется встроенный детектор утечки памяти, который называется C Runtime Library.Когда ваша программа завершает работу после возврата основной функции, CRT проверит кучу отладки вашего приложения.если у вас есть какие-либо блоки, все еще выделенные в куче отладки, значит, у вас утечка памятиC ++ ..

5 голосов
/ 07 июня 2011

Найдите в своем коде вхождения new и убедитесь, что все они встречаются в конструкторе с соответствующим удалением в деструкторе. Убедитесь, что это единственная возможная операция броска в этом конструкторе. Простой способ сделать это - обернуть все указатели в std::auto_ptr или boost::scoped_ptr (в зависимости от того, нужна ли вам семантика перемещения). Для всего будущего кода просто убедитесь, что каждый ресурс принадлежит объекту, который очищает ресурс в его деструкторе. Если вам нужна семантика перемещения, вы можете перейти на компилятор, который поддерживает ссылки на r-значения (я полагаю, VS2010) и создать конструкторы перемещения. Если вы не хотите этого делать, вы можете использовать различные хитрые приемы, связанные с добросовестным использованием swap, или попробовать библиотеку Boost.Move.

5 голосов
/ 07 июня 2011

Если вы используете gcc, есть gprof.

Я хотел бы узнать, как программист обнаруживает утечку памяти

Некоторые используют инструменты, некоторые делают то, что вы делаете,может также через рецензирование кода

Существует ли какой-либо стандарт или процедура, которой необходимо следовать, чтобы убедиться в отсутствии утечки памяти в программе

Для меня: всякий раз, когда я создаю динамическивыделенные объекты, я всегда ставлю код освобождения после, а затем заполнить код между.Это будет нормально, если вы уверены, что в коде не будет исключений.В противном случае я использую try-finally (я не часто использую C ++).

4 голосов
/ 15 сентября 2014

Visual Leak Detector (VLD) - это бесплатная, надежная система обнаружения утечек памяти с открытым исходным кодом для Visual C ++.

Когда вы запускаете свою программу под Visual Studioотладчик, Visual Leak Detector выдаст отчет об утечке памяти в конце сеанса отладки.Отчет об утечке включает в себя полный стек вызовов , показывающий, как были выделены любые утечки блоков памяти.Дважды щелкните строку в стеке вызовов, чтобы перейти к этому файлу и строке в окне редактора.

Если у вас есть только аварийные дампы, вы можете использовать команду Windbg !heap -l, онаобнаружить утечки блоков кучи.Лучше откройте опцию gflags: «Создать базу данных трассировки стека в пользовательском режиме», тогда вы увидите стек вызовов выделения памяти.

...