Почему динамически связанный импорт (в Windows) всегда загружается во время запуска приложения? - PullRequest
1 голос
/ 06 мая 2019

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

В Windows, когда загружается программа, все импорты функций разрешаются даже до вызова точки входа в программу. Пример: kernel32.dll!VirtualFree. Все необходимые библиотеки загружаются, затем вызывается точка входа в программу.

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

1 Ответ

1 голос
/ 06 мая 2019

На самом деле, , а не необходимо для всех библиотек DLL, от которых зависит приложение Windows для загрузки при запуске.Начиная с Visual C ++ 6.0 (1998), компоновщик MS поддерживает параметр /DELAYLOAD , который откладывает загрузку DLL до тех пор, пока не будет вызван один из ее экспортов.

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

Предположим, что тот же API с той же реализацией построен как статическая библиотека libfoo.libи как динамическая библиотека libfoo.dll.

Пока только одна программа нуждается в libfoo.dll в данный момент времени, тогда по крайней мере столько памяти потребляется в то время, сколько потреблялось бытой же программой, если она была статически связана с libfoo.lib.

Фактически, версия программы, которая загружает DLL, вполне может потреблять больше памяти, чем та, с которой связанастатическая библиотека.Это связано с тем, что при первой загрузке DLL в память загружается DLL-библиотека whole .Но на самом деле, это , а не , это тот случай, когда программа связана со статической библиотекой, статическая библиотека whole должна быть объединена с исполняемым файлом. статическая библиотека - это просто архив объектных файлов, из которого компоновщик по умолчанию извлекает только те, которые определяют символы, на которые ссылается программа, и связывает их в программу,игнорируя остальное.Таким образом, если программе не нужны все объектные файлы, заархивированные в libfoo.lib, то объем памяти, который ей потребуется при статическом связывании libfoo.lib, будет на меньше , чем объем памяти, необходимый для динамического связывания libfoo.dll.

Однако стоимость памяти начинает меняться в пользу DLL, как только более чем одной запущенной программе требуется libfoo.dll одновременно.Это связано с тем, что DLL состоит из отдельных разделов кода и данных, которые загрузчик может загружать отдельно.Каждая параллельная программа, которой требуется libfoo.dll, должна иметь свою собственную копию DLL data , но все они могут выполнять одну и ту же копию своего кода .После того, как libfoo.dll - разделы кода и данных - были загружены для первой программы, которая нуждается в этом, загрузчик должен загружать только новые копии своих данных для любых других параллельных программ, которым это необходимо.

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

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

Но у них есть еще один важныйвыгоды, даже для библиотек, которые могут быть использованы только одним приложением.Когда создается новый выпуск библиотеки foo, содержащий исправления или улучшения, единственный способ развернуть этот выпуск в программах, связанных со статической библиотекой libfoo.lib, - это перекомпоновать, перераспределить и переустановить все эти программы.Но пока новая версия libfoo сохраняет существующий API, ничего не нужно делать с программами, которые были связаны с libfoo.dll.Необходимо только распространить и установить новый выпуск libfoo.dll, и эти программы просто загрузят его при следующем запуске.Архитекторы приложений могут выбрать реализацию модулей специфичных для приложения функций в DLL именно для того, чтобы обновления этой функциональности могли быть развернуты без необходимости переустановки приложения конечными пользователями.

...