2012-04-24 3 views
6

Последующий вопрос Memory leaks when calling ITK from Visual Studio DLLVS2010 сообщает ложные утечки памяти для статических классов в DLL

Я усовершенствовал задачу простейшего примера.

struct A 
    { 
    public: 
    A() 
     { 
     mp_data = new int(0x42); 
     } 
    ~A() 
     { 
     delete mp_data; 
     } 
    int* mp_data; 
    }; 

A a; 

Когда такой глобальный класс определен в DLL, Visual Studio отладки CRT сообщает, что mp_data утечка на завершение работы приложения. Кто-нибудь знает обходное решение, за исключением отключения отчетов об утечке?

+0

Это может быть ошибка Visual Studio. См. Комментарии в соответствии с принятым ответом [здесь] (http://stackoverflow.com/questions/2204608/does-c-call-destructors-for-global-and-class-static-variables). –

+0

Нет, это не причина. Я проверил в отладчике, что '~ A()' действительно вызван. – Andrey

ответ

5

Если вы звоните _CrtDumpMemoryLeaks() в начало основной функции, то поведение ожидается, так как mp_data будет удалён после того, как был вызван _CrtDumpMemoryLeaks().

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

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

Статические объекты FYI с конструкторами и деструкторами считаются плохими в любом случае, потому что порядок, в котором они сконструированы/desctructed, не является детерминированным, и из-за этого статические объекты часто вводят ошибки, которые легко отлаживаются.

Редактировать комментарий по поводу Андрея: Вы могли бы попытаться отключить автоматический вызов _CrtDumpMemoryLeaks по телефону _CrtSetDbgFlag, чтобы сбросить флаг _CRTDBG_LEAK_CHECK_DF. Если это работает, вы можете добавить статический объект, который вызывает _CrtDumpMemoryLeaks() в своем деструкторе. Чтобы убедиться, что этот объект был разрушен последним, вы можете использовать #pragma init_seg(compiler) directive.

Нет подсказки, если это будет работать ... кроме этого, все остальные решения, скорее всего, потребуют изменения библиотеки ITK (что должно быть возможно, это библиотека с открытым исходным кодом в конце концов ?!).

+0

Это не совсем применимо, потому что (1) я не вызываю _CrtDumpMemoryLeaks() сам, VS runtime library делает это для меня; (2) на самом деле, статические объекты находятся в третьей стороне lib, которая находится вне моего контроля (по ссылке в вопросе) – Andrey

+0

@Andrey: see my edit – smerlin

+0

Спасибо, это работает! – Andrey

2

Любое из следующих решений проблемы.

(1) Создать поддельную зависимость DLL на MFC или

(2) Используйте решение, предложенное smerlin: добавьте этот код рядом с DllMain

struct _DEBUG_STATE 
    { 
    _DEBUG_STATE() {} 
    ~_DEBUG_STATE() { _CrtDumpMemoryLeaks(); } 
    }; 

#pragma init_seg(compiler) 
_DEBUG_STATE ds; 
2

Я ударил тот же симптом в ходе миграции внутренней библиотеки из статической привязки к динамической компоновке времени загрузки, и оказалось, что проблема в моем случае заключалась в том, что проект DLL и проект EXE были связаны с различными версиями библиотек времени исполнения/MFC VC++ (один был MBCS, а один был Unicode).

В моем случае приложение и библиотека использовали MFC, а деструктор _AFX_DEBUG_STATE, который активировал дамп утечки памяти CRT, вызывался дважды, для двух отдельных объектов - поскольку DLL и EXE связаны с разными DLL времени выполнения, статическое состояние во время выполнения эффективно дублировалось. Одна из DLL будет выгружать и сбросить утечки слишком рано и показать кучу ложных утечек. Переключение обоих проектов на использование одного и того же набора символов позволило разделить отдельную связь времени выполнения, а также разрешить ложные отчеты об утечке.

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

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

0

В приложениях MFC вы можете отключить автоматический сброс утечки памяти по телефону:

AfxEnableMemoryLeakDump(FALSE); 

Это поддерживается начиная с Visual Studio 2010. Для документации см here.

0

У меня были те же проблемы в Visual Studio 2015. Я пробовал все решения. Первое решение с fake-MFC-зависимость работало только в том случае, если вы выбрали опцию компилятора /MT в своей Dll. Таким образом, ваша Dll и основное приложение не будут использовать одну и ту же кучу. Но часто требуется /MD, например. если вы хотите совместно использовать STL-контейнер или строковые объекты между Dll и вашим основным приложением (Dll-граница). Если используется /MD, приложение и Dll используют одну и ту же кучу. Поэтому первое решение с фальшивой зависимостью MFC не сработало для меня.

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

Я нашел другое решение, поэтому у меня больше не было ложных ошибок памяти. Вам нужно использовать опцию /delayload для вашей Dll! Это все :-). Он работал для меня также с опцией компилятора /MD.

Here вы можете что-то прочитать о Dll-границе (зачем использовать /MD?). И here вы можете что-то прочитать о возможностях компилятора CRT вообще.

Смежные вопросы