Как найти утечку памяти в коде / проекте C ++?


180

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

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

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

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

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

29
«Я обычно заканчиваю в коде утечкой памяти». Если вы используете автоматические переменные, контейнеры и интеллектуальные указатели (и следуйте рекомендациям по использованию интеллектуальных указателей), утечки памяти должны быть крайне редкими. Помните, что почти во всех случаях вы должны использовать автоматическое управление ресурсами .
Джеймс МакНеллис

Дублирует проблемы, затронутые несколькими вопросами, такими как stackoverflow.com/questions/1502799/… и stackoverflow.com/questions/2820223/…
HostileFork говорит, что не доверяйте SE

1
@Hostile Вилка: «как можно избежать , чтобы , как правило , в конечном итоге в коде с утечками памяти» не охватывается этими ответами.
Док Браун

2
@Doc Brown: Мне тоже не хотелось это искать, но все это освещается в других местах, таких как stackoverflow.com/questions/45627/…
HostileFork говорит, что не доверяйте SE

1
Сделай сам детектор утечки: Вы можете поместить подозрительный код в бесконечный цикл, а затем открыть диспетчер задач, обычно даже небольшая утечка заполнит память за считанные секунды или минуты (это зависит от сложности вашего кода и вашего процессора). Если этого не произойдет, этот кусок кода, вероятно, не утечка.
Привет, мир

Ответы:


270

инструкции

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

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

1

Понять основы оператора. Оператор C ++ newвыделяет кучу памяти. deleteОператорских освобождает память кучи. Для каждого 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

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


3
извините за вопрос-комментарий, но как насчет параметров функции без указателей? someFunction("some parameter")я должен удалить "some parameter"в someFunction, после вызова функции, или они автоматически удаляются?
19greg96

1
спасибо за ссылку на Deleaker, это действительно удобный инструмент с аккуратной интеграцией в визуальную студию. Я мог бы сэкономить много времени, используя его. указал мне на строки, где я выделил память и не освободил ее. Отлично. И это дешево, по сравнению с другими искателями утечки памяти, которые я нашел.
this.myself

@ Джон Смит, пожалуйста, объясните, как правильно обращаться со случаями, аналогичными случаю 3; str2 = str1; // Плохой! Теперь 40 байтов невозможно освободить. как удалить ул 1 то ??
Нихар

1
Что если мы используем тип значения, такой как char *, int, float, ... и struct, как Vector, CString, и вообще не используем оператор 'new', это не вызовет утечку памяти, верно?
123iamking

Я просто здесь, чтобы сказать, что я не касался c ++ почти 14 лет ... но я горжусь тем, что понял и помню, как сделать все это благодаря книге на С ++, которой я все еще владею и читаю, когда я Мне скучно с C #. Эта книга - «Эффективный С ++» Скотта Митчелла. Боже, я любил эту книгу. Спасибо Скотт!
Джон

33

Вы можете использовать некоторые методы в своем коде для обнаружения утечки памяти. Самый распространенный и самый простой способ обнаружить - определить макрос, скажем, 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 ++ для перегрузки и / или переопределения оператора new и оператора delete для перехвата вызовов выделения и освобождения памяти и, таким образом, отладки программы для использования памяти. Он часто включает определение макроса с именем DEBUG_NEW и превращает новое в нечто новое (_ FILE _, _ LINE _) для записи информации о файле / строке при выделении.Microsoft Visual C ++ использует эту технику в своих классах Microsoft Foundation. Есть несколько способов расширить этот метод, чтобы избежать использования переопределения макросов, но при этом отображать информацию о файлах / строках на некоторых платформах. Есть много присущих этому методу ограничений. Он применяется только к C ++ и не может улавливать утечки памяти функциями C, такими как malloc. Тем не менее, он может быть очень простым в использовании и очень быстрым по сравнению с некоторыми более полными решениями отладчика памяти.


4
это #defineможет operator newпривести к перегрузке и появлению ошибок компилятора. Даже если вам удастся преодолеть это, перегруженные функции не будут решены. Хотя техника хороша, иногда требуется много изменений кода.
Iammilind

1
@iammilind: Конечно, этот метод не является полностью излечимым решением всех проблем и, конечно, не применим во всех ситуациях.
Наваз

@Chris_vr: auto_ptrне будет работать со стандартными контейнерами, такими как std::vectorи std::listт. Д. См .: stackoverflow.com/questions/111478/…
Nawaz

Хорошо. ФАЙЛ и строка описаны. Что это такое operator newи какие версии вы используете?

14

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

  • если вам нужно сделать свое собственное динамическое распределение памяти, напишите 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 ++, и что это значит, если у вас есть класс, которому принадлежит указатель (или что это значит, если у вас есть класс, который содержит указатель на объект, которым он не владеет).

Я использую auto_pointer объекта, это означает, что он удалит все другие указатели объекта класса внутри него.
Chris_vr

@Chris_vr: если у вас есть конкретный вопрос об auto_pointer, я бы предложил вам задать новый вопрос, включая пример.
Док Браун

Многие посты говорят мне, что vector <> не гарантирует освобождение памяти при очистке. Я лично тестировал файлы подкачки и т. Д. И пришел к выводу, что vector <> протекает, особенно при динамическом использовании. Я не понимаю, как vector <> можно посоветовать при самостоятельном динамическом размещении с использованием 'new' и корректной очистки. Во встроенных программах я избегаю использовать vector <> для динамических вещей из-за всех утечек. Там я использую new или std :: list
bart s

Я набираю вторую команду из-за количества символов. К сожалению, в моем встроенном c ++ у меня есть старый c ++ (98?), Который не имеет shrink_to_fit для вектора ... Однако встроенная программа на 100% уверена, что она полностью завершится сбоем при исчерпании памяти с использованием динамического вектора <>
bart s


8
  1. Загрузите средства отладки для Windows .
  2. Используйте gflagsутилиту для включения трассировки стека в пользовательском режиме.
  3. Используйте, UMDHчтобы сделать несколько снимков памяти вашей программы. Сделайте снимок до того, как будет выделена память, и сделайте второй снимок после того момента, когда вы считаете, что в вашей программе произошла утечка памяти. Возможно, вы захотите добавить паузы или подсказки в вашу программу, чтобы дать вам возможность запустить UMDHи сделать снимки.
  4. Запустите UMDHснова, на этот раз в своем режиме, который делает различие между двумя снимками. Затем он сгенерирует отчет, содержащий стеки вызовов о предполагаемых утечках памяти.
  5. Восстановите свои предыдущие gflagsнастройки, когда закончите.

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


1
Я предпочитаю Deleaker и Valgrind вместо стандартного профилировщика
z0r1fan

8

Запустить «Валгринд» можно:

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

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

Инструкция по применению "Valgrind"

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

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

3) В вашей оболочке запустите:

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(что не было освобождено) был вызван.

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


6

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

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

Кто-то использует инструменты, кто-то делает то, что вы делаете

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

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


Некоторое время мы не можем удалить выделенные в конструкторе. Что делать в этом случае.
Chris_vr

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

  2. Этот форум обсуждает несколько способов избежать утечки памяти в C / C ++.


5

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


не всегда возможно удалить выделенную память в конструкторе. Как справиться с этой ситуацией
Chris_vr

@Chris_vr Что ты имеешь в виду? Если все члены вашего указателя scope_ptrs, и каждый инициализируется индивидуально, то все успешно построенные будут удалять свои указатели, а остальные все равно не будут держать указатели на выделенную память. Я приведу пример через несколько часов, когда вернусь домой с работы.
Манкарс

@Chris_vr: если у вас есть конкретный пример, опубликуйте его как новый вопрос, чтобы мы могли обсудить его там.
Док Браун

5

Вы можете использовать инструмент Valgrind для обнаружения утечек памяти.

Также, чтобы найти утечку в конкретной функции, используйте exit (0) в конце функции, а затем запустите ее с Valgrind

`$` valgrind ./your_CPP_program 

5

Обзор автоматических контроллеров утечки памяти

В этом ответе я сравниваю несколько различных средств проверки утечки памяти в простом, понятном примере утечки памяти.

Прежде всего, посмотрите на эту огромную таблицу в вики ASan, которая сравнивает все инструменты, известные человеку: https://github.com/google/sanitizers/wiki/AddressSanitizerComparisonOfMemoryTools/d06210f759fec97066888e5f27c7e722832b0924

Анализируемый пример будет:

main.c

#include <stdlib.h>

void * my_malloc(size_t n) {
    return malloc(n);
}

void leaky(size_t n, int do_leak) {
    void *p = my_malloc(n);
    if (!do_leak) {
        free(p);
    }
}

int main(void) {
    leaky(0x10, 0);
    leaky(0x10, 1);
    leaky(0x100, 0);
    leaky(0x100, 1);
    leaky(0x1000, 0);
    leaky(0x1000, 1);
}

GitHub вверх по течению .

Мы попытаемся увидеть, насколько четко различные инструменты указывают нам на утечки вызовов.

tcmalloc от gperftools от Google

https://github.com/gperftools/gperftools

Использование в Ubuntu 19.04:

sudo apt-get install google-perftools
gcc -ggdb3 -o main.out main.c -ltcmalloc
PPROF_PATH=/usr/bin/google-pprof \
  HEAPCHECK=normal \
  HEAPPROFILE=ble \
  ./main.out \
;
google-pprof main.out ble.0001.heap --text

Результат выполнения программы содержит анализ утечки памяти:

WARNING: Perftools heap leak checker is active -- Performance may suffer
Starting tracking the heap
Dumping heap profile to ble.0001.heap (Exiting, 4 kB in use)
Have memory regions w/o callers: might report false leaks
Leak check _main_ detected leaks of 272 bytes in 2 objects
The 2 largest leaks:
Using local file ./main.out.
Leak of 256 bytes in 1 objects allocated from:
        @ 555bf6e5815d my_malloc
        @ 555bf6e5817a leaky
        @ 555bf6e581d3 main
        @ 7f71e88c9b6b __libc_start_main
        @ 555bf6e5808a _start
Leak of 16 bytes in 1 objects allocated from:
        @ 555bf6e5815d my_malloc
        @ 555bf6e5817a leaky
        @ 555bf6e581b5 main
        @ 7f71e88c9b6b __libc_start_main
        @ 555bf6e5808a _start


If the preceding stack traces are not enough to find the leaks, try running THIS shell command:

pprof ./main.out "/tmp/main.out.24744._main_-end.heap" --inuse_objects --lines --heapcheck  --edgefraction=1e-10 --nodefraction=1e-10 --gv

If you are still puzzled about why the leaks are there, try rerunning this program with HEAP_CHECK_TEST_POINTER_ALIGNMENT=1 and/or with HEAP_CHECK_MAX_POINTER_OFFSET=-1
If the leak report occurs in a small fraction of runs, try running with TCMALLOC_MAX_FREE_QUEUE_SIZE of few hundred MB or with TCMALLOC_RECLAIM_MEMORY=false, it might help find leaks more re
Exiting with error code (instead of crashing) because of whole-program memory leaks

и вывод google-pprofсодержит анализ использования кучи:

Using local file main.out.
Using local file ble.0001.heap.
Total: 0.0 MB
     0.0 100.0% 100.0%      0.0 100.0% my_malloc
     0.0   0.0% 100.0%      0.0 100.0% __libc_start_main
     0.0   0.0% 100.0%      0.0 100.0% _start
     0.0   0.0% 100.0%      0.0 100.0% leaky
     0.0   0.0% 100.0%      0.0 100.0% main

Вывод указывает нам на две из трех утечек:

Leak of 256 bytes in 1 objects allocated from:
        @ 555bf6e5815d my_malloc
        @ 555bf6e5817a leaky
        @ 555bf6e581d3 main
        @ 7f71e88c9b6b __libc_start_main
        @ 555bf6e5808a _start
Leak of 16 bytes in 1 objects allocated from:
        @ 555bf6e5815d my_malloc
        @ 555bf6e5817a leaky
        @ 555bf6e581b5 main
        @ 7f71e88c9b6b __libc_start_main
        @ 555bf6e5808a _start

Я не уверен, почему третий не появился

В любом случае, когда обычно, когда что-то протекает, это случается много раз, и когда я использовал это в реальном проекте, я просто очень легко указывал на функцию утечки.

Как уже упоминалось в выходных данных, это приводит к значительному замедлению выполнения.

Дополнительная документация по адресу:

Смотрите также: Как использовать TCMalloc?

Проверено в Ubuntu 19.04, google-perftools 2.5-2.

Адрес Sanitizer (ASan) также от Google

https://github.com/google/sanitizers

Ранее упоминалось по адресу: Как найти утечку памяти в коде / проекте C ++? ТОДО против tcmalloc.

Это уже интегрировано в GCC, так что вы можете просто сделать:

gcc -fsanitize=address -ggdb3 -o main.out main.c
./main.out 

и результаты выполнения:

=================================================================
==27223==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 4096 byte(s) in 1 object(s) allocated from:
    #0 0x7fabbefc5448 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x10c448)
    #1 0x55bf86c5f17c in my_malloc /home/ciro/test/main.c:4
    #2 0x55bf86c5f199 in leaky /home/ciro/test/main.c:8
    #3 0x55bf86c5f210 in main /home/ciro/test/main.c:20
    #4 0x7fabbecf4b6a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x26b6a)

Direct leak of 256 byte(s) in 1 object(s) allocated from:
    #0 0x7fabbefc5448 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x10c448)
    #1 0x55bf86c5f17c in my_malloc /home/ciro/test/main.c:4
    #2 0x55bf86c5f199 in leaky /home/ciro/test/main.c:8
    #3 0x55bf86c5f1f2 in main /home/ciro/test/main.c:18
    #4 0x7fabbecf4b6a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x26b6a)

Direct leak of 16 byte(s) in 1 object(s) allocated from:
    #0 0x7fabbefc5448 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x10c448)
    #1 0x55bf86c5f17c in my_malloc /home/ciro/test/main.c:4
    #2 0x55bf86c5f199 in leaky /home/ciro/test/main.c:8
    #3 0x55bf86c5f1d4 in main /home/ciro/test/main.c:16
    #4 0x7fabbecf4b6a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x26b6a)

SUMMARY: AddressSanitizer: 4368 byte(s) leaked in 3 allocation(s).

который четко идентифицирует все утечки. Ницца!

ASan также может выполнять другие классные проверки, такие как запись за пределами поля: обнаружен разрыв стека

Протестировано в Ubuntu 19.04, GCC 8.3.0.

Valgrind

http://www.valgrind.org/

Ранее упоминалось по адресу: https://stackoverflow.com/a/37661630/895245

Использование:

sudo apt-get install valgrind
gcc -ggdb3 -o main.out main.c
valgrind --leak-check=yes ./main.out

Вывод:

==32178== Memcheck, a memory error detector
==32178== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==32178== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==32178== Command: ./main.out
==32178== 
==32178== 
==32178== HEAP SUMMARY:
==32178==     in use at exit: 4,368 bytes in 3 blocks
==32178==   total heap usage: 6 allocs, 3 frees, 8,736 bytes allocated
==32178== 
==32178== 16 bytes in 1 blocks are definitely lost in loss record 1 of 3
==32178==    at 0x483874F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==32178==    by 0x10915C: my_malloc (main.c:4)
==32178==    by 0x109179: leaky (main.c:8)
==32178==    by 0x1091B4: main (main.c:16)
==32178== 
==32178== 256 bytes in 1 blocks are definitely lost in loss record 2 of 3
==32178==    at 0x483874F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==32178==    by 0x10915C: my_malloc (main.c:4)
==32178==    by 0x109179: leaky (main.c:8)
==32178==    by 0x1091D2: main (main.c:18)
==32178== 
==32178== 4,096 bytes in 1 blocks are definitely lost in loss record 3 of 3
==32178==    at 0x483874F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==32178==    by 0x10915C: my_malloc (main.c:4)
==32178==    by 0x109179: leaky (main.c:8)
==32178==    by 0x1091F0: main (main.c:20)
==32178== 
==32178== LEAK SUMMARY:
==32178==    definitely lost: 4,368 bytes in 3 blocks
==32178==    indirectly lost: 0 bytes in 0 blocks
==32178==      possibly lost: 0 bytes in 0 blocks
==32178==    still reachable: 0 bytes in 0 blocks
==32178==         suppressed: 0 bytes in 0 blocks
==32178== 
==32178== For counts of detected and suppressed errors, rerun with: -v
==32178== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)

Итак, еще раз, все утечки были обнаружены.

Смотрите также: Как мне использовать valgrind для поиска утечек памяти?

Протестировано в Ubuntu 19.04, valgrind 3.14.0.


4

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

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

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


4

MTuner - это бесплатный мультиплатформенный инструмент для профилирования памяти, обнаружения и анализа утечек, поддерживающий компиляторы MSVC, GCC и Clang. Особенности включают в себя:

  • история использования памяти на временной шкале и блоки оперативной памяти
  • мощная фильтрация операций с памятью на основе кучи, метки памяти, временного диапазона и т. д.
  • SDK для ручного инструментария с полным исходным кодом
  • поддержка непрерывной интеграции через использование командной строки
  • навигация по дереву стека вызовов и карте дерева
  • гораздо более.

Пользователи могут профилировать любые программные платформы с кросс-компиляторами GCC или Clang. MTuner поставляется со встроенной поддержкой платформ Windows, PlayStation 4 и PlayStation 3.


Это должен быть принятый ответ. Это отличный инструмент, и он может обрабатывать объемы распределения / освобождения, которые другие не могут.
Серж Рогач

3

В Windows вы можете использовать CRT debug heap .

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

Да, не используйте ручное управление памятью (если вы когда-либо звоните deleteили delete[]вручную, то вы делаете это неправильно). Используйте RAII и умные указатели, ограничьте выделение кучи абсолютным минимумом (в большинстве случаев автоматических переменных будет достаточно).


3

Отвечая на вторую часть вашего вопроса,

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

Да, есть. И это одно из ключевых отличий между C и C ++.

В C ++ вы никогда не должны вызывать newили deleteв своем пользовательском коде. RAII - очень распространенный метод, который в значительной степени решает проблему управления ресурсами. Каждый ресурс в вашей программе (ресурс - это все, что необходимо получить, а затем освободить: дескрипторы файлов, сетевые сокеты, соединения с базой данных, а также обычное выделение памяти и, в некоторых случаях, пары вызовов API (BeginX ( ) / EndX (), LockY (), UnlockY ()) должны быть заключены в класс, где:

  • конструктор получает ресурс (путем вызова, newесли ресурс является выделением памяти)
  • деструктор освобождает ресурс,
  • копирование и присваивание либо предотвращаются (делая приватными конструктор копирования и операторы присваивания), либо реализуются для правильной работы (например, путем клонирования базового ресурса)

Этот класс затем создается локально, в стеке или как член класса, а не путем вызова newи сохранения указателя.

Вам часто не нужно определять эти классы самостоятельно. Контейнеры стандартной библиотеки также ведут себя таким образом, что любой объект, сохраненный в a, std::vectorосвобождается при уничтожении вектора. Так опять же , не хранить указатель в контейнер (который требовал бы вы назвать newи delete), а , скорее , объект сам (который дает вам управление памятью бесплатно ). Аналогично, классы интеллектуальных указателей можно использовать для простого переноса объектов, которые просто должны быть выделены new, и управления их временем жизни.

Это означает, что когда объект выходит из области видимости, он автоматически уничтожается, а его ресурс освобождается и очищается.

Если вы будете делать это последовательно по всему коду, у вас просто не будет утечек памяти. Все, что могло вытечь, связано с деструктором, который гарантированно будет вызван, когда управление покидает область, в которой был объявлен объект.


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

@Chris: Предполагается, что объект, на который указывает смарт-указатель, имеет деструктор, который выполняет необходимую очистку, или объект содержит элементы, которые сами имеют деструкторы для выполнения необходимой очистки. По сути, до тех пор, пока каждый объект заботится о себе (очищает после себя, когда он уничтожается), и пока каждый объект хранится по значению, а не как указатель, все, что нужно освободить, будет освобождено.
Джалф

3

AddressSanitizer (ASan) - это быстрый детектор ошибок памяти. Он находит ошибки переполнения use-after-free и {heap, stack, global} -buffer в программах на C / C ++. Находит:

  • Использовать после освобождения (разыменование висящего указателя)
  • Переполнение буфера динамической памяти
  • Переполнение буфера в стеке
  • Глобальное переполнение буфера
  • Использовать после возврата
  • Ошибки порядка инициализации

Этот инструмент очень быстрый. Среднее замедление инструментальной программы составляет ~ 2x.


Смотрите особенно LeakSanitizer
Габриэль Devillers

0

В дополнение к инструментам и методам, представленным в других разделах, инструменты статического анализа кода могут использоваться для обнаружения утечек памяти (а также других проблем). Бесплатный надежный инструмент - Cppcheck. Но есть много других доступных инструментов. В Википедии есть список инструментов для статического анализа кода.


-1

Убедитесь, что вся куча памяти успешно освобождена. Нет необходимости, если вы никогда не выделяете память в куче. Если вы это сделаете, подсчитайте, сколько раз вы использовали память malloc, и подсчитайте, сколько раз вы освобождаете память.


-3

Ни «new», ни «delete» никогда не должны использоваться в коде приложения. Вместо этого создайте новый тип, который использует идиому «менеджер / работник», в которой класс менеджера выделяет и освобождает память и перенаправляет все другие операции рабочему объекту.

К сожалению, это больше работы, чем должно быть, потому что в C ++ нет перегрузки «оператора». Еще больше работы при наличии полиморфизма.

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.