Используют ли (статически связанные) библиотеки DLL кучу, отличную от основной программы?

Я новичок в программировании Windows, и я просто "потерял" два часа на поиске ошибки, о которой все, кажется, знают: вы не можете создать объект в куче в DLL и уничтожить его в другой DLL (или в основной программе),

Я почти уверен, что в Linux/Unix это НЕ так (если это так, пожалуйста, скажите это, но я уверен, что я делал это тысячи раз без проблем...).

На данный момент у меня есть пара вопросов:

1) Используют ли статически связанные библиотеки DLL кучу, отличную от основной программы?

2) Статически связанная DLL отображается в том же пространстве процесса основной программы? (Я совершенно уверен, что ответ здесь - это большое ДА, иначе было бы бессмысленно передавать указатели от функции в основной программе к функции в DLL).

Я говорю о простой / обычной DLL, а не о сервисах COM/ATL

РЕДАКТИРОВАТЬ: под "статически связаны" я имею в виду, что я не использую LoadLibrary для загрузки DLL, но я связываюсь с библиотекой заглушки

3 ответа

Решение

Библиотеки DLL / exes должны будут ссылаться на реализацию библиотек времени выполнения C.

В случае библиотек C Windows Runtime вы можете указать, хотите ли вы ссылаться на следующее:

  1. Однопоточная библиотека времени выполнения C (поддержка однопоточных библиотек прекращена)
  2. Многопоточная DLL / Многопоточная отладочная DLL
  3. Статические библиотеки времени выполнения.
  4. Еще немного (Вы можете проверить ссылку)

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

Теперь это зависит от того, с какой библиотекой C времени выполнения связана библиотека, о которой вы говорите. Предположим, скажем, используемая вами DLL была связана со статической библиотекой времени выполнения C, а код вашего приложения (содержащий основную функцию) связан с многопоточной DLL времени выполнения C, тогда, если вы передадите указатель на память, выделенную в DLL к вашей основной программе и попробуйте освободить ее там или наоборот, это может привести к неопределенному поведению. Итак, основной причиной являются библиотеки времени выполнения C. Пожалуйста, выбирайте их тщательно.

Пожалуйста, найдите больше информации о поддерживаемых библиотеках C здесь и здесь

Цитата из MSDN:

Внимание ! Не смешивайте статические и динамические версии библиотек времени выполнения. Наличие в процессе более одной копии библиотек времени выполнения может вызвать проблемы, поскольку статические данные в одной копии не передаются другой копии. Компоновщик не позволяет связывать статические и динамические версии в одном файле.exe, но вы все равно можете получить две (или более) копии библиотек времени выполнения. Например, библиотека динамической компоновки, связанная со статическими (не DLL) версиями библиотек времени выполнения, может вызвать проблемы при использовании с файлом.exe, который был связан с динамической (DLL) версией библиотек времени выполнения, (Вам также следует избегать смешивания отладочной и не отладочной версий библиотек в одном процессе.)

Давайте сначала разберемся с распределением кучи и стеком в ОС Windows относительно наших приложений /DLL. Традиционно операционная система и библиотеки времени выполнения поставляются с реализацией кучи.

  1. В начале процесса ОС создает кучу по умолчанию, называемую кучей процесса. Куча процесса используется для распределения блоков, если не используется другая куча.
  2. Языковые среды выполнения также могут создавать отдельные кучи внутри процесса. (Например, время выполнения C создает собственную кучу.)
  3. Помимо этих выделенных куч, прикладная программа или одна из многих загруженных динамически подключаемых библиотек (DLL) могут создавать и использовать отдельные кучи, называемые частными кучами.
  4. Эти кучи располагаются поверх диспетчера виртуальной памяти операционной системы во всех системах виртуальной памяти.
  5. Давайте обсудим больше о CRT и связанных кучах:
    1. Распределитель времени выполнения C/C++ (CRT): предоставляет malloc() и free(), а также операторы new и delete.
    2. CRT создает такую ​​дополнительную кучу для всех своих распределений (дескриптор этой кучи CRT хранится внутри библиотеки CRT в глобальной переменной с именем _crtheap) как часть его инициализации.
    3. CRT создает свою собственную частную кучу, которая находится поверх кучи Windows.
    4. Куча Windows - это тонкий слой, окружающий распределитель времени выполнения Windows (NTDLL).
    5. Распределитель времени выполнения Windows взаимодействует с Распределителем виртуальной памяти, который резервирует и фиксирует страницы, используемые ОС.

Ваша DLL и EXE ссылка на многопоточные статические библиотеки CRT. Каждая создаваемая вами DLL и исполняемая программа имеет свою собственную кучу, то есть _crtheap. Распределения и перераспределения должны происходить из соответствующей кучи. То, что динамически выделяется из DLL, не может быть отменено из исполняемого файла и наоборот.

Что ты можешь сделать? Скомпилируйте наш код в DLL, и exe использует /MD или /MDd для использования многопоточной и DLL-версии версии библиотеки времени выполнения. Следовательно, и DLL, и exe связаны с одной и той же библиотекой времени выполнения C и, следовательно, с одним _crtheap. Распределение всегда связано с отменой выделения в одном модуле.

Если у меня есть приложение, которое компилируется как.exe, и я хочу использовать библиотеку, я могу либо статически связать эту библиотеку из файла.lib, либо динамически связать эту библиотеку из файла.dll.

Каждый связанный модуль (т.е. каждый.exe или.dll) будет связан с реализацией времени выполнения C или C++. Сами времена выполнения - это библиотека, которая может быть статически или динамически связана с различными конфигурациями потоков.

Говоря о статически связанных dll, вы описываете установку, в которой приложение.exe динамически связывается с библиотекой.dll, а эта библиотека статически связывается со средой выполнения? Я предполагаю, что это то, что вы имеете в виду.

Также стоит отметить, что каждый модуль (.exe или.dll) имеет собственную область действия для статики, т.е. глобальная статика в.exe не будет тем же экземпляром, что и глобальная статика с тем же именем в.dll.

Следовательно, в общем случае нельзя предполагать, что код, работающий внутри разных модулей, использует одну и ту же реализацию среды выполнения, более того, они не будут использовать один и тот же экземпляр какого-либо статического состояния.

Поэтому при работе с объектами или указателями, которые пересекают границы модуля, необходимо соблюдать определенные правила. Распределения и освобождения должны происходить в одном и том же модуле для любого заданного адреса. В противном случае кучи не будут совпадать, и поведение не будет определено.

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

Могут существовать и другие проблемы, например, windows определяет определенные действия, например, как сбои выделения обрабатываются для каждого потока, а не для каждого модуля. Это означает, что код, выполняемый в модуле A в потоке, настроенном модулем B, также может работать непредвиденным образом.

Другие вопросы по тегам