2009-10-28 3 views
8

У меня есть EXE-файл с использованием DLL-файла, который использует другой DLL-файл. Такая ситуация возникла:Освобождение памяти, выделенной в другой DLL

В DLL файл 1:

class abc 
{ 
    static bool FindSubFolders(const std::string & sFolderToCheck, 
           std::vector<std::string> & vecSubFoldersFound); 
} 

В DLL файл 2:

void aFunction() 
{ 
    std::vector<std::string> folders; 
    std::string sLocation; 
    ... 
    abc::FindSubFolders(sLocation, folders) 
} 

В режиме выпуска, все работает отлично. Но в режиме отладки, я пришел с недостаточностью утверждения в деструкторе одного из std::strings в векторе папки (если папки выходят из области видимости в конце прекращения функции):

dbgheap.c : line 1274

/* 
* If this ASSERT fails, a bad pointer has been passed in. It may be 
* totally bogus, or it may have been allocated from another heap. 
* The pointer MUST come from the 'local' heap. 
*/ 
_ASSERTE(_CrtIsValidHeapPointer(pUserData)); 

Я предполагаю, что это связано с тем, что память была выделена в кучу DLL-файла 1, но освобождается в файле DLL 2.

Комментарий в dbgheap.c кажется довольно настойчивым, что это проблема.

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

+2

DONT. IGNORE. УКАЗАНИЯ – KeatsPeeks

+22

НЕ. ИГНОРИРОВАНИЕ. ЭТО. ЭТО. ЗАЧЕМ. Я СПРОСИЛ. = P – Smashery

+0

Просто хочу знать * почему * это проблема. – Smashery

ответ

11

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

Если у вас есть контроль над тем, как скомпилированы оба файла DLL, обязательно используйте многопоточные DLL-файлы DLL (/ MDd) или многопоточные DLL-файлы (/ MD) для библиотеки времени выполнения. Таким образом, оба файла DLL будут использовать одну и ту же систему времени выполнения и использовать одну и ту же кучу.

Недостатком является то, что вам необходимо установить систему выполнения вместе с вашим приложением (для этого Microsoft предлагает установщик). Он отлично работает на вашей машине разработки, поскольку Visual Studio также устанавливает эту среду выполнения, но на только что установленном компьютере сообщается о отсутствующих DLL-файлах.

+0

Мои свойства проекта были неправильными - у меня не было набора Debug DLL (/ MDd) - теперь он работает нормально. Благодаря! – Smashery

6

Скорее всего, сборка выпуска имеет ту же проблему, но релиз сборки не утверждают. Они просто игнорируют проблему. Вы никогда не увидите проблемы. Или вы можете увидеть повреждение данных. Или вы можете увидеть сбой. Возможно, только ваши пользователи будут испытывать ошибки, которые вы просто не можете воспроизвести.

Не игнорируйте утверждения CRT.

Вы всегда должны использовать соответствующий дезактиватор (тот, который соответствует обычно используемому распределителю). Если вы используете статические библиотеки CRT в своих DLL-файлах, DLL-файлы используют разные кучи. Вы не можете освободить память на кучи. Выделите и освободите блок памяти, используя одну и ту же кучу.

Если вы используете общие библиотеки CRT в своих DLL-файлах, то они должны использовать одну и ту же кучу, и вы можете выделить в один DLL-файл и освободить его в другом.

+2

ср. Раймонд Чен: http://blogs.msdn.com/oldnewthing/archive/2006/09/15/755966.aspx –

+0

+1 - Спасибо! – Smashery

5

Это проблема только в том случае, если приложение или один (или более) DLL-файлы связаны со статической версией стандартной библиотеки. Это было решено примерно десять лет назад MS, выпустив общую библиотечную версию стандартной библиотеки. Это связано с тем, что каждая версия стандартной библиотеки будет создавать собственную внутреннюю кучу и, таким образом, с несколькими кучами, вы должны освободить память до правильной кучи. Используя общую версию стандартной библиотеки, все они используют одну и ту же кучу.

В настоящее время это стандартная практика для приложения, и все DLL-файлы должны быть построены для использования динамической версии стандартной библиотеки.

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

6

Как гласит другое, проблема может быть решена путем обеспечения совместного использования ЭЛТ между этими двумя модулями. Но есть общие сценарии, где этот контракт трудно обеспечить.

Причина в том, что обеспечение связи с общим CRT не будет работать, если EXE и DLL не свяжутся с тем же CRT версии (как в 6.0, 7.0, 8.0). Например, если вы берете DLL, созданную в VC6.0, и пытаетесь использовать ее с EXE-сборкой в ​​VS2010, вы получите ту же проблему, что и раньше. Две версии CRT будут загружены в ваш процесс, и каждый будет использовать свою собственную кучу для распределения, независимо от того, использует ли ваш EXE и DLL «общий» CRT, они не будут одинаковыми.

Лучшей практикой для API было бы удостовериться, что объекты, расположенные на одной стороне, также уничтожены на одной стороне. Я знаю, что это звучит уродливо, но это единственный способ гарантировать совместимость библиотеки DLL.

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