я использую _CrtDumpMemoryLeaks (); из stdlib.h и crtdbg.h для обнаружения утечек памяти, но я заметил кое-что странное в моем коде.
Если я сделаю:
int _tmain(int argc, _TCHAR* argv[])
{
MyClass* myClass = new MyClass();
_CrtDumpMemoryLeaks(); //I get a memory leak warning
}
Однако, если я сделаю:
class MyClass
{
public:
char* NewChar();
};
char* MyClass::NewChar()
{
char* test = new char[100];
return test;
}
MyClass myClass; //Globally declared
int _tmain(int argc, _TCHAR* argv[])
{
char* charPointer = myClass.NewChar();
_CrtDumpMemoryLeaks(); //No warnings
}
Я не должен получить предупреждение, так как моя программа вышла (сразу после _CrtDumpMemoryLeaks ()) а еще был новый символ, который не был удален?
Как я могу обнаружить эти утечки памяти?
Также, используя тот же пример выше, если я добавлю код:
char* anotherPointer = charPointer; //previously filled
delete[] anotherPointer;
Будет ли это удалить новый символ из класса, предотвращая утечки памяти, или я должен вызвать delete on charPointer также?
Если вы хотите отловить (или прилично попытаться отловить) глобальные утечки объектов, попробуйте установить флаг отладки CRT _CRTDBG_LEAK_CHECK_DF в начале основного. Флаг заставляет сброс обнаруженных утечек после глобальные деструкторы.
Чтобы ответить на ваши вопросы:
Разве я не должен получить предупреждение, так как моя программа закрылась (сразу после _CrtDumpMemoryLeaks ()), и все еще был новый символ, который не был удален?
Определите «предупреждение». Призыв к _CrtDumpMemoryLeaks()
должен свалить все то, что является выдающимся в то время. Ваша программа, выходящая после, не будет делать еще один дамп, если не настроена для этого.
Как я могу обнаружить эти утечки памяти?
Они должны быть правильно обнаружены при условии, что вы используете CRT отладки и имеете _Crt
настройка конфигурации правильно, что это в основном является по умолчанию.
Следующий код устанавливает _Crt
система дампов для выгрузки всех объектов по требованию и непосредственно перед окончательным выходом (после main()
закончен и глобальные статики уничтожены).
class MyLeak
{
public:
MyLeak() { new unsigned char[1024]; }
char * NewChar() { return new char[1024]; }
};
MyLeak myLeak;
int main(int argc, char *argv[])
{
int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
tmpFlag |= _CRTDBG_LEAK_CHECK_DF;
_CrtSetDbgFlag(tmpFlag);
_CrtMemState ms = {0};
_CrtMemCheckpoint(&ms);
char *ptr = myLeak.NewChar();
_CrtMemDumpAllObjectsSince(&ms);
OutputDebugString("Exiting main()\n");
return EXIT_SUCCESS;
}
Отладочный выходной журнал
Dumping objects ->
{69} normal block at 0x000000000048B800, 1024 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
Exiting main()
Detected memory leaks!
Dumping objects ->
{69} normal block at 0x000000000048B800, 1024 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
{68} normal block at 0x000000000048B390, 1024 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
Обратите внимание, что первый дамп записывает только внутреннее распределение, поскольку я использовал контрольную точку, а затем вызов dump-Since. Второй дамп (вызывается после main()
закончено) все еще записывает их обоих, так как они оба выдающиеся.
То, что вы создаете утечку после динамического выделения (которое было предоставлено от объекта в глобальном пространстве памяти, но не имеет ничего общего с выделением, это просто код, выделяющий память и возвращающий ее вам), выглядит неправильно. Вы должны получить объектный дамп все выдающиеся распределения ЭЛТ с любым _CrtDumpMemoryLeaks()
вызывать с момента запуска программы.
Думаю об этом. Глобальная переменная myClass
имеет статическую продолжительность хранения. Он будет уничтожен после закрывающей скобки main
когда программа заканчивается. _CrtDumpMemoryLeaks
() не может утвердительно определить утечку как деструктор MyClass
еще не (правильно) был вызван.
Я не должен получить предупреждение, так как моя программа закрылась (сразу после_CrtDumpMemoryLeaks ())
Да, вы должны получить предупреждение, но не из-за выхода, …
а еще был новый символ, который не был удален?
…но из-за этого, т. е. потому что массив символов это не было удалено.
Как я могу обнаружить эти утечки памяти?
Вы уверены, что скомпилировали программу с _DEBUG #defined? Если вы это сделали, это должно быть обнаружено. (Я не могу проверить себя сейчас и не использовал это целую вечность, поэтому я не могу ручаться за это.)
Также, используя тот же пример выше, если я добавлю код:
char* anotherPointer = charPointer; //previously filled
delete [] anotherPointer; `
Будет ли это удалять новый символ изнутри класса, предотвращая утечки памяти, или я должен также вызвать delete в charPointer?
Это удалит динамически распределенный массив символов. После этого charPointer
это свисающий указатель, которые нельзя использовать больше — ни разыменовывать, ни удалять [] ‘d. (То же самое относится и к anotherPointer
.) Повторное удаление удаленного массива, через тот же указатель или другую переменную, не допускается и вызывает Неопределенное поведение.
Вы связываетесь с отладочными библиотеками? Если вы этого не сделаете, вы не будете получать сообщения о неосвобожденных блоках памяти. Подсказка: используйте параметр / MDd.
Обратите внимание, что вопреки тому, что предлагает имя функции, все, что она делает, это печатает список блоков памяти, которые вы еще не освободили. Вызывая его в конце main (), вы заставляете его отчитываться о блоках, которые вы явно разместили, но явно не освободили. Поэтому, если у вас есть одноэлементные объекты, размещаемые динамически, они будут сообщаться как утечка, тогда как вы вполне законно можете освободить их, используя функцию, подключенную через механизм _atexit ().