Memory Leaks - lanit-tercom-school/grouplock GitHub Wiki
Загрузить можно отсюда:
- https://visualstudiogallery.msdn.microsoft.com/7c40a5d8-dd35-4019-a2af-cb1403f5939c/
- http://vld.codeplex.com/
По существу, это обертка над C++ CRT.
• После загрузки установить (куда угодно, но лучше по тому пути, который прописан изначально).
• Скопировать VLD библиотеку .lib
в Вашу папку с Visual Studio C++ (у меня это внутренняя папка студии VC) в папку lib.
• Скопировать VLD заголовочный файл .h
из папки inclide в Вашу папку с Visual Studio C++ (у меня это внутренняя папка студии VC) в папку include.
• В файле программы перед главной точкой входа включить файл заголовка vld.h
. Лучше, чтобы он был до остальных заголовочных файлов (но это не обязательно), но строго после stdafx.h
.
• Запустить проект в режиме отладки
Отчет обо всех обнаруженных утечках памяти будет отображаться в окне вывода отладчика при выходе из вашей программы. Двойной щелчок по номеру строки файла с исходным текстом в отчете приведет к этому файлу и строке в окне редактора, что позволяет легко перемещаться по коду.
Примечание: При создании релиз-версии вашей программы VLD не будет включен в исполняемый файл. Так что его безопасно оставлять подключенным, и это не приведет к каким-либо ухудшениям рабочих характеристик или любой другой нежелательной ситуации.
Создание детектора. VLD создавалось как улучшенная замена детектора утечки памяти, встроенного в Visual C ++. Поэтому в VLD используется примерно тот же метод, что и во встроенном детекторе, а именно CRT Debug Heap с некоторыми добавлениями. Но этот новый детектор имеет значительные усовершенствования - в первую очередь, указывает полный путь, что полезно для обнаружения и устранения утечек.
Встроенный детектор.
Встроенный детектор довольно прост на самом деле. Вместе с началом работы программы библиотека CRT запускает ветвь очистки. Если встроенный детектор включен, то он запускает проверку на утечку памяти как часть процедуры очистки. Проверка утечки памяти просто смотрит на отладочную ветвь: если какие-либо пользовательские блоки по-прежнему существуют в куче, то это должны быть утечки памяти. Отладочная версия malloc
сохраняет файл и номер строки в заголовочный файл (то есть запоминается каждое выделение памяти). Когда встроенный детектор определяет утечку памяти, он просто смотрит внутрь заголовка, чтобы получить имя файла и номер строки. Затем он передает эту информацию в отладчик, где все это отображается.
Обратите внимание, что встроенный детектор обнаруживает утечки, просто делая снимок кучи непосредственно перед тем, как процесс завершается и определяя, есть ли какие-либо утечки, на основе этого снимка. Снимок кучи только говорит нам, если есть утечки, но не говорит, как они просочились и где. Очевидно, чтобы определить это "как" мы также должны получить путь. Но для этого мы должны быть в состоянии контролировать все распределение во время выполнения. Это главное, что отличает этот детектор от встроенного.
К счастью для нас, компания Microsoft создала простой способ контролировать каждое распределение, сделанное из кучи отладки: крючки распределения (allocation hooks(AH)). AH - просто функция обратного вызова, которая будет вызываться непосредственно перед тем как производится каждое распределение из кучи отладки. Microsoft представила функцию __CrtSetAllocHook_
, которая регистрирует функцию AH в куче. Когда отладчик вызывает АН, одним из аргументов является идентификационный номер, который однозначно определяет каждое распределение - это в основном серийный номер для каждого выделенного блока памяти. Но места в заголовке блока памяти не хватает для того, чтобы записать любую информацию непосредственно в нем, поэтому мы можем использовать этот уникальный идентификационный номер в качестве ключа для отображения каждого блока в любых данных, которые мы хотим записать.
Теперь, когда у нас есть способ получать уведомления каждый раз, когда блок будет выделен, а также способ однозначно идентифицировать каждое распределение, все, что осталось сделать, это делать запись в стеке вызовов каждый раз, когда происходит распределение. Опять же, Microsoft предоставила нам инструмент: на этот раз это функция StackWalk64
. Она является частью отладки библиотеки DBGHELP.DLL. Каждый раз, когда вызывается StackWalk64
, она возвращает структуру STACKFRAME64
, которая может быть повторно использована в качестве входных данных для следующего вызова StackWalk64
. Можно неоднократно использовать этот путь, пока не будет достигнут конец стека.
Теперь мы можем контролировать каждое распределение, и для каждого распределения можем получить и записать путь в стеке. Единственная проблема, которая остается, это гарантировать, чтобы функция АН регистрировала выделение памяти, как только программа начинает выполняться. Это может быть очень просто решено путем создания глобального экземпляра объекта класса ++ C. Конструктор _CrtSetAllocHook
будет работать как программа инициализации. Но как мы можем гарантировать, что наш конструктор будет вызван в первую очередь, и что функция АН будет установлена до того, как будут построены другие глобальные объекты? К сожалению, нет абсолютных гарантий. Но мы можем подойти очень близко: использовать конкретную директиву препроцессора, которая явно говорит компилятору, чтобы наша глобальная переменная строилась как можно скорее: #pragma init_seg
(компилятор). Объекты в этом сегменте должны быть построены первыми и только потом объекты из сегмента "библиотеки" и объекты из сегмента "пользователь". Сегмент "пользователь" по умолчанию используется сегмент для глобальных объектов. Вообще говоря, никакие нормальные пользовательские объекты никогда не должны быть помещены в сегмент "компилятор", так что это обеспечивает довольно сильную уверенность, что наш глобальный объект будет построен перед любыми пользовательскими объектами.
Обнаружение утечек памяти.
Поскольку глобальные объекты уничтожаются в порядке, обратном порядку их построения, наш глобальный объект будет уничтожен после любых пользовательских объектов, поэтому мы можем исследовать кучу, так же, как это делает встроенный детектор. Если мы найдем блок в куче, который не был освобожден, то это утечка, и мы можем посмотреть его стек вызовов с использованием уникального идентификационного номера, записанного с помощью нашей функции АН.
Все, что мы имеем в стеке вызовов, представляет собой множество программных адресов в шестнадцатеричной форме. Для того, чтобы эти адреса были нам понятны, нужно перевести их на язык, понятный человеку: имя файлы и номера строк (и имена функций тоже). Опять же, Microsoft помогает нам с инструментами: из API мы можем использовать обработчик символов, чтобы получить имена файлов, номера строк и имена функций (SymGetLineFromAddr64
преобразует адреса в исходные имена файлов и номера строк, а SymFromAddr
преобразует адреса в имена символов).
Текст взят из статьи разработчика с сайта с доработками и сокращениями:
http://www.codeproject.com/Articles/9815/Visual-Leak-Detector-Enhanced-Memory-Leak-Detectio
Полезная вроде как статься, мало ли на будущее.
https://habrahabr.ru/company/sebbia/blog/243537/
Утечка памяти (memory leak) — процесс неконтролируемого уменьшения объёма свободной оперативной или виртуальной памяти компьютера, связанный с ошибками в работающих программах, вовремя не освобождающих ненужные уже участки памяти, или с ошибками системных служб контроля памяти.
Этот сбой при освобождении ранее выделенной памяти, — это одна из наиболее трудно обнаруживаемых ошибок в приложениях C/C++. Быть может, пользователь и не заметит однократной утечки каких-нибудь 32Кб памяти (а ведь это целые 5% от 640Кб, которых «хватит всем»), но постоянно теряя сложные иерархические структуры или массивы размером больше INT_MAX
(которые мы так любим создавать на 64-битной архитектуре) мы обречем его на страдания, а наш продукт на провал.
Динамическая память является ограниченным ресурсом, а управление динамической памятью программы обычно осуществляется библиотекой языка программирования, которая сама работает поверх динамической памяти, предоставляемой операционной системой.
Утечки памяти приводят к тому, что потребление памяти программой неконтролируемо возрастает, в результате рано или поздно вступают в действие архитектурные ограничения среды исполнения (операционной системы, виртуальной машины, ЭВМ), и тогда новое выделение памяти становится невозможным. Небольшая утечка памяти сначала может остаться незамеченной, но постепенно нарастающая может приводить к различным симптомам, от снижения производительности до аварийного завершения приложения из-за нехватки памяти. Более того, приложение, в котором происходит утечка памяти, может использовать всю доступную память и привести к аварийному завершению другого приложения, в результате чего может быть непонятно, какое приложение отвечает за сбой. Даже безобидная на первый взгляд утечка памяти может быть признаком других проблем, требующих устранения.
Отладчик Visual Studio и библиотеки времени выполнения C (CRT) предоставляют средства для обнаружения утечек памяти.
Способы предотвращения.
Не допускать ситуации вроде бы и не трудно — воспользуемся правилом «класть на место всё что взяли», но на практике это сильно осложняется человеческим фактором (банальная невнимательность), хитростью архитектуры и нелинейным порядком выполнения операторов, например, из-за применения исключений.
Существуют различные способы предотвращения утечек памяти.
1.Отказ от динамической памяти. Например, FORTRAN-77 полностью отказывается от применения механизмов динамического распределения памяти, что исключает подобные ошибки, но существенно ограничивает функциональность программ.
2.Владеющие указатели (или умные указатели). Владеющие указатели позволяют в той или иной мере согласовать время жизни указателя и время жизни объекта, на который он ссылается. Тем не менее, использование владеющих указателей не помогает в случае циклических ссылок между объектами.
3.Сборка мусора (garbage collector).
Некоторые языки программирования (например, Оберон, Java, языки платформы .NET) предоставляют средства, позволяющие автоматически освобождать неиспользуемую память. Сборщики мусора решают также и проблему циклических ссылок, но сборка мусора является ресурсоёмкой операцией. За использование подобных средств приходится расплачиваться быстродействием системы, и, главное, сборка мусора вносит неожиданные паузы в программу, что недопустимо в системах реального времени.
4.Перезапуск программы.
В тех случаях, когда устранить утечки памяти не представляется возможным, например, при использовании кода, поставляемого в виде программных модулей и изготовленного сторонними разработчиками, применяют своеобразный способ игнорирования утечек. Код, подверженный утечкам, размещают в отдельной программе, а эту программу с нужной периодичностью перезапускают. Запуски и перезапуски программы выполняются внешней программой, которая также подаёт исходные данные и забирает результаты. Поскольку при завершении программы вся память, затребованная ей у операционной системы, возвращается операционной системе, такой метод не позволяет утечкам приобрести катастрофический характер.
Рассмотрим следующий фрагмент кода на C++ как пример:
/*1*/ char *pointer = NULL;
/*2*/ for( int i = 0; i < 10; i++ ) {
/*3*/ pointer = new char[100];
/*4*/ }
/*5*/ delete [] pointer;
В этом примере на 3-й строке создается объект в динамической памяти. Код на 3-й строке выполняется 10 раз, причём каждый следующий раз адрес нового объекта перезаписывает значение, хранящееся в указателе pointer
. На 5-й строке выполняется удаление объекта, созданного на последней итерации цикла. Однако первые 9 объектов остаются в динамической памяти, и одновременно в программе не остаётся переменных, которые бы хранили адреса этих объектов. Т.е. в 5-й строке невозможно ни получить доступ к первым 9 объектам, ни удалить их.
Обнаружение утечек.
Для профессиональных языков программирования существуют специальные программы-профилировщики, позволяющие обнаружить в числе прочего и утечки памяти.
Для некоторых языков программирования существуют статические анализаторы кода, выявляющие элементы программы, потенциально способные приводить к логическим ошибкам, в том числе и к утечке памяти. Примитивный вариант такого анализатора реализует практически любой компилятор языка высокого уровня, в виде выдачи так называемых предупреждений (warnings
) — сообщений о наличии в программе конструкций, формально не нарушающих синтаксис языка, но потенциально ошибочных.
Существуют библиотеки для отладки использования памяти, помогающие следить за выделением и освобождением памяти во время работы программы.
Основным средством для обнаружения утечек памяти в Visual Studio является отладчик и отладочные функции кучи библиотеки времени выполнения C (CRT).
Чтобы включить отладочные функции кучи, вставьте в программу следующие операторы:
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
Для правильной работы функций CRT операторы #include
должны следовать в приведенном здесь порядке.
Включение заголовочного файла crtdbg.h
сопоставляет функции malloc
и free
с их отладочными версиями, _malloc_dbg
и free
, которые отслеживают выделение и освобождение памяти. Это сопоставление используется только в отладочных построениях, в которых определен _DEBUG
. В окончательных построениях используются первоначальные функции malloc
и free
.
Оператор #define
сопоставляет базовые версии функций кучи CRT соответствующим отладочным версиям. Если оператор #define
не используется, дамп утечки памяти будет менее подробным.
После того как с помощью этих операторов будут включены отладочные функции кучи, можно поместить вызов _CrtDumpMemoryLeaks
перед точкой выхода приложения для отображения отчета об утечке памяти перед завершением работы приложения:
_CrtDumpMemoryLeaks();
Если у приложения несколько точек выхода, не требуется вручную размещать вызовы функции _CrtDumpMemoryLeaks
в каждой точке выхода. Вызов функции _CrtSetDbgFlag
в начале приложения приведет к автоматическому вызову функции _CrtDumpMemoryLeaks
в каждой точке выхода. Необходимо установить два показанных здесь битовых поля:
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
По умолчанию _CrtDumpMemoryLeaks
выводит отчет об утечке памяти в область Отладка окна Вывод. _CrtSetReportMode
можно использовать для перенаправления отчета в другое расположение.
Если используется библиотека, она может переустановить вывод в другое расположение. В этом случае можно вернуть вывод обратно в окно Вывод, как показано ниже:
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG );
Интерпретация отчета об утечке памяти.
Если приложение не определяет _CRTDBG_MAP_ALLOC, _CrtDumpMemoryLeaks отображает отчет об утечке памяти, выглядящий следующим образом:
Detected memory leaks! Dumping objects -> {18} normal block at 0x00780E80, 64 bytes long. Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD Object dump complete.
Если приложение определяет _CRTDBG_MAP_ALLOC
, отчет об утечке памяти выглядит следующим образом:
Detected memory leaks! Dumping objects -> C:\PROGRAM FILES\VISUAL STUDIO\MyProjects\leaktest\leaktest.cpp(20) : {18} normal block at 0x00780E80, 64 bytes long. Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD Object dump complete.
Разница заключается в том, что во втором отчете отображается имя файла и номер строки, в которой впервые было произведено выделение утекающей памяти.
Независимо от определения _CRTDBG_MAP_ALLOC
, в отчете об утечке памяти отображаются следующие сведения:
• Номер выделения памяти, в этом примере — 18.
• Тип блока, в этом примере — normal.
• Расположение памяти в шестнадцатеричном формате, в этом примере — 0x00780E80.
• Размер блока, в этом примере — 64 bytes.
• Первые 16 байт данных в блоке, в шестнадцатеричном формате.
В отчете об утечке памяти блок памяти может определяться как обычный, клиентский или CRT.
Обычный блок — это обыкновенная память, выделенная программой.
Клиентский блок — особый тип блока памяти, используемой программами MFC для объектов, для которых требуется деструктор. Оператор new в MFC создает либо обычный, либо клиентский блок, в соответствии с создаваемым объектом.
Блок CRT — это блок памяти, выделенной библиотекой CRT для внутреннего использования.
Освобождение этих блоков производится библиотекой CRT. Поэтому маловероятно увидеть их в отчете об утечке памяти — разумеется, если не возникнет серьезный сбой, например, повреждение библиотеки CRT.
Существуют два других типа блоков памяти, которые никогда не отображаются в отчетах об утечке памяти.
Свободный блок — это блок памяти, которая была освобождена. Это по определению означает, что она не имеет отношения к утечкам.
Пропускаемый блок — это память, специально помеченная для исключения из отчета об утечке памяти.
Эти способы работают для памяти, выделенной с помощью стандартной функции malloc библиотеки CRT. Однако если программа выделяет память с использованием оператора new C++, необходимо переопределить оператор new, если требуется, чтобы в отчете об утечке памяти отображались имя файла и номера строк. Это можно сделать с помощью блока кода, аналогичного приведенному ниже:
#ifdef _DEBUG
#ifndef DBG_NEW
#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
#define new DBG_NEW
#endif
#endif // _DEBUG
Задание точек останова для номера выделения памяти.
Номер выделения памяти сообщает, когда был выделен утекающий блок памяти. Например, блок с номером выделения памяти 18 — это 18-й блок памяти, выделенный во время выполнения программы. В отчете CRT учитываются все выделения блоков памяти во время выполнения. Сюда входят выделения, произведенные библиотекой CRT и другими библиотеками, такими как MFC. Поэтому блок с номером выделения памяти 18 может не быть 18-м блоком памяти, выделенным вашим кодов. Как правило, не будет.
Номер выделения можно использовать для того, чтобы задать точку останова в том месте, где выделяется память.
Установка точки останова для выделения памяти с помощью окна контрольных значений.
- Задайте точку останова недалеко от начала приложения, затем запустите приложение.
- Когда выполнение приложения остановится в точке останова, откройте окно Контрольные значения.
- В окне Контрольные значения введите
_crtBreakAlloc
в столбце Имя.
Если используется многопоточная версия DLL библиотеки CRT (параметр /MD), добавьте контекстный оператор:
{,,ucrtbased.dll}_crtBreakAlloc
. - Нажмите клавишу ВВОД.
Отладчик выполнит оценку вызова и поместит результат в столбец Значение. Это значение будет равно -1, если в местах выделения памяти не задано ни одной точки останова. - В столбце Значение замените отображаемое значение номером выделения памяти, на котором нужно приостановить выполнение.
После задания точки останова для номера выделения памяти можно продолжить отладку. Проследите за тем, чтобы программа была запущена в таких же условиях, как и в предыдущий раз, чтобы порядок выделения памяти не изменился. Когда выполнение программы будет приостановлено на заданном выделении памяти, с помощью окна Стек вызовов и других окон отладчика определите условия выделения памяти. Затем можно продолжить выполнение программы и проследить, что происходит с этим объектом и почему выделенная ему память освобождается неправильно.
Точки останова для выделения памяти можно также задать в коде. Это можно сделать двумя способами.
_crtBreakAlloc = 18;
или
_CrtSetBreakAlloc(18);
Сравнение состояний памяти.
Другая технология для обнаружения утечек памяти включает получение "снимков" состояния памяти приложения в ключевых точках. Чтобы получить снимок состояния памяти в заданной точке приложения, создайте структуру _CrtMemState
и передайте ее функции _CrtMemCheckpoint
. Функция поместит в структуру снимок текущего состояния памяти:
_CrtMemState s1; _CrtMemCheckpoint( &s1 );
```c++
Функция `_CrtMemCheckpoint` поместит в структуру снимок текущего состояния памяти.
Чтобы вывести содержимое структуры `_CrtMemState`, передайте ее функции `_ CrtMemDumpStatistics`:
`_CrtMemDumpStatistics( &s1 );`
Функция `_ CrtMemDumpStatistics` выводит дамп состояния памяти, который выглядит примерно таким образом:
0 bytes in 0 Free Blocks. 0 bytes in 0 Normal Blocks. 3071 bytes in 16 CRT Blocks. 0 bytes in 0 Ignore Blocks. 0 bytes in 0 Client Blocks. Largest number used: 3071 bytes. Total allocations: 3764 bytes.
Чтобы определить, произошла ли утечка памяти на отрезке кода, можно сделать снимок состояния памяти перед ним и после него, а затем сравнить оба состояния с помощью функции `_ CrtMemDifference`:
_CrtMemCheckpoint( &s1 ); // memory allocations take place here _CrtMemCheckpoint( &s2 ); if ( _CrtMemDifference( &s3, &s1, &s2) ) _CrtMemDumpStatistics( &s3 );
Функция `_CrtMemDifference` сравнивает состояния памяти s1 и s2 и возвращает результат в (s3), представляющий собой разницу s1 и s2.
Еще один способ поиска утечек памяти заключается в размещении вызовов `_CrtMemCheckpoint` в начале и конце программы с последующим использованием `_CrtMemDifference` для сравнения результатов. Если `_CrtMemDifference` показывает утечку памяти, можно добавить дополнительные вызовы функции `_CrtMemCheckpoin`t, чтобы разделить программу с помощью двоичного поиска, пока не будет найден источник утечки.
**Ложные срабатывания.**
В некоторых случаях `_CrtDumpMemoryLeaks` может ошибочно диагностировать утечку памяти. Это может произойти в случае использования библиотеки, в которой внутренние выделения отмечены как `_NORMAL_BLOCK` вместо `_CRT_BLOCK` или `_CLIENT_BLOCK`. В таком случае функция `_CrtDumpMemoryLeaks` не может различать пользовательские выделения и внутренние выделения библиотеки.Если глобальные деструкторы для выделений библиотеки выполняются после точки вызова функции `_CrtDumpMemoryLeaks`, каждое внутреннее выделение библиотеки принимается за утечку памяти. Предыдущие версии библиотеки стандартных шаблонов, предшествовавшие Visual Studio .NET, приводили к тому, что функция `_CrtDumpMemoryLeaks` сообщала о таких ложных утечках, но в последних выпусках это было исправлено.
Текст взят с сайта MSDN и Wikipedia:
https://msdn.microsoft.com/ru-ru/library/x98tx3cf.aspx
https://ru.wikipedia.org/wiki/%D0%A3%D1%82%D0%B5%D1%87%D0%BA%D0%B0_%D0%BF%D0%B0%D0%BC%D1%8F%D1%82%D0%B8
### Debug CRT С++
Для использования Debug CRT надо подключить соответствующий header и включить использование _Debug Heap Alloc Map_. Делается это всего несколькими строками кода:
Подключение Debug CRT
```c++
#ifdef _DEBUG
#include <crtdbg.h>
#define _CRTDBG_MAP_ALLOC
#endif
После этих действий при выделении памяти через new
и malloc()
данные будут оборачиваться в специальную структуру _CrtMemBlockHeader
. С помощью этой обертки мы сможем узнать имя файла и строку, в которой резервировалась ликнутая память, ее объем и сами данные. Все записи объединены в двусвязный список, поэтому по нему можно легко пробежаться и найти проблемные участки.
Структура _CrtMemBlockHeader
typedef struct _CrtMemBlockHeader
{
struct _CrtMemBlockHeader * pBlockHeaderNext;
struct _CrtMemBlockHeader * pBlockHeaderPrev;
char* szFileName;
int nLine;
size_t nDataSize;
int nBlackUse;
long lRequest;
unsigned char gap[nNoMansLandSize];
unsigned char data[nDataSize];
unsigned char anotherGap[nNoMansLandSize];
} _CrtMemBlockHeader;
Чтобы пройтись по этому списку, нужно воспользоваться функцией _CrtDumpMemoryLeaks()
. Она не принимает никаких параметров, а просто выводит список утекших блоков памяти. Но, к сожалению, она ничего не говорит нам о файле и строке, в которых выделялась память. Результат работы этой функции выглядит примерно так:
Вывод _CrtDumpMemoryLeaks()
Detected memory leaks!
Dumping objects ->
{163} normal block at 0x00128788, 4 bytes long.
Data: < > 00 00 00 00
{162} normal block at 0x00128748, 4 bytes long.
Data: < > 00 00 00 00
Object dump complete.
Вот оно как: в Microsoft Visual C++ 6.0 в файле crtdbg.h
имело место переопределение функции new
, которое должно было точно показать файл и строку, в котором происходило выделение памяти. Но оно не давало желаемого результата — FILE:LINE
всегда разворачивались в crtdbg.h file line 512
. В следующих версиях Microsoft вообще убрали эту фичу, и весь груз ответственности лег на программистов. Сделать нормальный вывод можно с помощью следующего переопределения:
Переопределение new
#define new new( _NORMAL_BLOCK, __FILE__, __LINE__)
Эту строчку желательно вынести в какой-нибудь общий заголовочный файл и подключать его после crtdbg.h
. Теперь перед нами стоит задача записать все это в какой-нибудь лог или хотя бы выводить в консоль. Для перенаправления вывода нам потребуются две функции: _CrtSetReportMode
и _CrtSetReportFile
. Вторым параметром _CrtSetReportFile
может быть хендл нашего лог-файла или флаг вывода в stdout
.
Перенаправление вывода
_CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
// выводим все в stdout
_CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT );
У этого метода есть еще одна проблемка — он выводит информацию о памяти, которая не утекла, а просто не успела вернуться. Это, например, может быть какая-нибудь глобальная переменная или объект. Нам нужно как-то удалить эти куски памяти из вывода _CrtDumpMemoryLeaks()
. Делается это следующим образом:
Ограничение зоны действия _CrtDumpMemoryLeaks()
int _tmain(int argc, _TCHAR* argv[])
{
_CrtMemState _ms;
_CrtMemCheckpoint(&_ms);
// some logic goes here...
_CrtMemDumpAllObjectsSince(&_ms);
return 0;
}
Мы записываем начальное состояние памяти в специальную структуру с помощью функции _CrtMemCheckpoint()
, а в конце, используя _CrtMemDumpAllObjectsSince()
, выводим все, что утекло после того, как мы сделали слепок памяти.
Вот так вот, с помощью нехитрых функций Debug CRT, мы можем достаточно эффективно бороться с мемори ликами в нашей программе. Конечно, это не заменит серьезных библиотек по отлову утечек, но вполне подойдет для небольших проектов.
https://xakep.ru/2011/05/14/57056/
// test.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "windows.h"
#ifdef _DEBUG
#include <crtdbg.h>
#define _CRTDBG_MAP_ALLOC // enable generation of debug heap alloc map
#define new new( _NORMAL_BLOCK, __FILE__, __LINE__) // redefine "new" to get file names in output
#endif
class T // simple test class to demonstrate global initialization memory leak
{
int* m;
public:
T() { m = new int(); };
~T() { delete m; };
};
T b;
int _tmain(int argc, _TCHAR* argv[])
{
#ifdef _DEBUG
_CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE ); // enable file output
_CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT ); // set file to stdout
_CrtMemState _ms;
_CrtMemCheckpoint(&_ms); // now forget about objects created before
#endif
for (int i = 0; i < 24; i++) new int(); // create test stuff
#ifdef _DEBUG
_CrtMemDumpAllObjectsSince(&_ms); // dump leaks
#endif
return 0;
}
И инструкция по ссылке (там все хорошо описано и у меня все работало)