утечка памяти: невозможно разбить номер памяти - PullRequest
5 голосов
/ 25 июня 2010

Я пытаюсь найти проблему утечки памяти.

Мой проект - это диалоговый проект на основе ATL, использующий DirectShow и стандартную библиотеку.

Я получаю в общей сложности 45 памятив моей программе - все 24 байта.

В моем stdafx.h есть # define'd _CRTDBG_MAP_ALLOC и т. д., а также DEBUG_NEW для получения номеров файлов и строк для каждой утечки памяти.

Однако номера строк файла не печатаются.Все блоки памяти являются «обычными» блоками и выглядят так:

{180} normal block at 0x003E6008, 24 bytes long. Data: <  >  _>   > W   > A0 AE 3E 00 B0 5F 3E 00 A0 AE 3E 00 57 00 00 00 

Я попытался добавить следующую строку в начало _tWinMain ()

_CrtSetBreakAlloc(180);

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

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

Наконец, вот мой _tWinMain () - я вызываю _CrtDumpMemoryLeaks () непосредственно перед выходом.

int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow){
    _CrtSetBreakAlloc(180);

    HRESULT hRes = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
    ATLASSERT(SUCCEEDED(hRes));


    ::DefWindowProc(NULL, 0, 0, 0L);
    AtlInitCommonControls(ICC_BAR_CLASSES);

    //HINSTANCE hInstRich = ::LoadLibrary(CRichEditCtrl::GetLibraryName());

    hRes = _Module.Init(NULL, hInstance);
    ATLASSERT(SUCCEEDED(hRes));

    int nRet = Run(lpstrCmdLine, nCmdShow);

    _Module.Term();
    ::CoUninitialize();

    _CrtDumpMemoryLeaks();

    return nRet;
}

Ответы [ 2 ]

7 голосов
/ 26 июня 2010

Два предложения.

Во-первых, то, что создается до main (или эквивалентного) запуска, уничтожается после завершения main. Вызов _CrtDumpMemoryLeaks в конце main может дать вам ложные срабатывания. (Или это ложные отрицания?) Деструкторы глобальных объектов еще не запущены, а atexit обратные вызовы еще не запущены, поэтому вывод утечки будет включать в себя выделения, которые просто еще предстоит правильно освободить.

(Я подозреваю, что именно поэтому ваши глобальные объекты появляются с утечкой. Возможно, в коде нет ничего плохого, и действительно вполне возможно, что он очищается должным образом - код очистки просто еще не запустился, когда _CrtDumpMemoryLeaks называется.)

Вместо этого вам нужно дать указание библиотеке времени выполнения вызвать для вас _CrtDumpMemoryLeaks, в самом конце, после завершения всех обратных вызовов atexit и деструкторов глобальных объектов. Тогда вы увидите только подлинные утечки. Этот фрагмент сделает свое дело. Придерживайтесь в начале main:

_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)|_CRTDBG_LEAK_CHECK_DF);

Во-вторых, если вышеприведенное показывает подлинные утечки из вещей, которые выполняются до main, вы можете сделать небольшую хитрость, чтобы заставить ваш собственный код работать в значительной степени, прежде чем что-либо еще увидит. Затем вы можете установить _crtBreakAlloc, прежде чем произойдет какое-либо распределение. Просто вставьте следующий код в собственный файл .cpp:

#include <crtdbg.h>

#ifdef _DEBUG

#pragma warning(disable:4074)//initializers put in compiler reserved initialization area
#pragma init_seg(compiler)//global objects in this file get constructed very early on

struct CrtBreakAllocSetter {
    CrtBreakAllocSetter() {
        _crtBreakAlloc=<allocation number of interest>;
    }
};

CrtBreakAllocSetter g_crtBreakAllocSetter;

#endif//_DEBUG

(Я подозреваю, что код в сегменте инициализации компилятора может хорошо выполняться до инициализации stdin и stdout и т. П., И, безусловно, до того, как будут созданы какие-либо глобальные объекты, поэтому вам может быть сложно выполнить что-то более сложное, чем выше!)

(Сколько бы это ни стоило, я придерживаюсь мнения, и в течение некоторого времени я считал, что распределение до начала main почти всегда плохо. Из-за этого трудно убирать за собой, и трудно отследить, что происходит. Это, конечно, удобно, но вы, кажется, всегда платите за это позже. Это совет, который гораздо легче раздать, чем реализовать, особенно, как часть большой команды. )

0 голосов
/ 25 июня 2010

У меня было несколько глобальных переменных (таблицы поиска, которые возвращали ссылки CString на сообщения об ошибках), которые я удалил из программы. Как только я это сделал - утечки памяти нет.

Спасибо за ваши комментарии, ребята.

Интересно - мне придется исследовать другой способ реализации поиска ошибок.

Я делал что-то вроде:

CString sError = "error at line x: " + g_map.lookup(hrError);

Карта ошибок реализована как объект, который обертывает доступ к std :: map, и его деструктор работает нормально. Когда я размещаю этот объект карты в куче и освобождаю его, он не сообщает об утечках памяти. Может быть, так я конкатенирую CString ....

...