Загружаются ли общие объекты/DLL разными процессами в разные области памяти?

Я пытаюсь выяснить, как операционная система обрабатывает несколько несвязанных процессов, загружающих одну и ту же DLL/общую библиотеку. Меня интересуют операционные системы Linux и Windows, но в меньшей степени и Mac. Я предполагаю, что ответы на мои вопросы будут одинаковыми для всех операционных систем.

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

Это лучшее объяснение, которое я нашел для Windows:

Система поддерживает счетчик ссылок для каждого процесса для всех загруженных модулей. Вызов LoadLibrary увеличивает счетчик ссылок. Вызов функции FreeLibrary или FreeLibraryAndExitThread уменьшает счетчик ссылок. Система выгружает модуль, когда его счетчик ссылок достигает нуля или когда процесс завершается (независимо от счетчика ссылок). - http://msdn.microsoft.com/en-us/library/windows/desktop/ms684175%28v=vs.85%29.aspx

Но оставляет некоторые вопросы.

1.) Загружают ли несвязанные процессы одну и ту же DLL избыточно (то есть DLL существует в памяти более одного раза) вместо использования подсчета ссылок? (IE, в собственное адресное пространство каждого процесса, насколько я понимаю)

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

2.) если это так, то какой смысл считать библиотеки DLL, когда вы загружаете их несколько раз в одном и том же процессе? Какой смысл дважды загружать одну и ту же DLL в один и тот же процесс? Единственная возможная причина, которую я могу придумать, заключается в том, что если EXE-файл ссылается на две библиотеки DLL, а одна из них ссылается на другую, то будет по крайней мере два вызова LoadLibrar() и два вызова FreeLibrary() для одной и той же библиотеки.

Я знаю, кажется, что я отвечаю здесь на свои вопросы, но я просто постулирую. Я хотел бы знать наверняка.


person Brandon    schedule 28.06.2013    source источник
comment
Убедитесь, что вы понимаете виртуальную память и пейджинг. Фактические адреса, которые видят процессы, могут отличаться независимо от того, загружена ли отдельная копия библиотеки или нет.   -  person Kerrek SB    schedule 29.06.2013


Ответы (1)


Совместно используемая библиотека или DLL будет загружена один раз для части кода и несколько раз для любых частей данных, доступных для записи [возможно, с помощью «копирования при записи», поэтому, если у вас есть большой кусок памяти, который в основном читается, но небольшой части записываются, все библиотеки DLL могут использовать одни и те же части, если они не были изменены по сравнению с исходным значением].

Однако ВОЗМОЖНО, что DLL будет загружена более одного раза. При загрузке DLL загружается базовый адрес, с которого начинается код. Если у нас есть некоторый процесс, который использует, скажем, две DLL, которые из-за их предыдущей загрузки используют один и тот же базовый адрес [поскольку другие процессы, использующие это, не используют оба], тогда одна из DLL должна будет загружаться снова по другому базовому адресу. Для большинства DLL это довольно необычно. Но это может случиться.

Смысл подсчета ссылок при каждой загрузке заключается в том, что он позволяет системе узнать, когда можно безопасно выгрузить модуль (когда счетчик ссылок равен нулю). Если у нас есть две отдельные части системы, обе из которых хотят использовать одну и ту же DLL, и обе они загружают эту DLL, вы на самом деле не хотите, чтобы система зависала, когда первая часть системы закрывает DLL. Но мы также не хотим, чтобы DLL оставалась в памяти, когда вторая часть системы закрыла DLL, потому что это было бы пустой тратой памяти. [Представьте, что это приложение представляет собой процесс, который выполняется на сервере, и каждую неделю с сервера загружаются новые DLL, поэтому каждую неделю загружается «последняя» DLL (у которой другое имя). Через несколько месяцев вся память этих приложений будет заполнена «старыми, неиспользуемыми» DLL]. Конечно, есть и такие сценарии, как то, что вы описываете, когда DLL загружает другую DLL с помощью вызова LoadLibrary, а основной исполняемый файл загружает ту же самую DLL. Опять же, вам нужно два вызова FreeLibrary, чтобы закрыть его.

person Mats Petersson    schedule 28.06.2013
comment
Я не понимаю, что вы имеете в виду под записываемыми частями данных или копированием при записи. Я понимаю подсчет ссылок, меня сбила с толку часть ссылки, в которой говорилось: Система выгружает модуль, когда его счетчик ссылок достигает нуля или когда процесс завершается (независимо от счетчика ссылок) . - person Brandon; 29.06.2013
comment
Итак, есть счетчик ссылок НА ПРОЦЕСС и еще один счетчик ссылок, указывающий, сколько процессов используют конкретную DLL. Если процесс завершается (вызывает exit или происходит какой-либо сбой), то счетчик ссылок на процесс не используется для определения данных. Записываемые части данных - глобальные переменные в DLL должны быть для каждого процесса, иначе это может привести к довольно опасной утечке между процессами. Посмотрите в google copy-on-write, это объяснит намного лучше, чем я могу в этом посте. - person Mats Petersson; 29.06.2013
comment
что из-за их предыдущей загрузки используется один и тот же базовый адрес @MatsPetersson. Меня это немного смущает. ОС использует физические адреса, не так ли? И ОС может дать разные виртуальные адреса для двух DLL, если процесс использует обе, то почему они должны быть одинаковыми? - person pooya13; 10.02.2020
comment
Если DLL загружается дважды, она должна быть (хотя бы частично) загружена в разные физические местоположения в сети или иметь один и тот же виртуальный адрес. Вероятно, в коде будут задействованы некоторые абсолютные адреса, такие как указатели на данные или функции, которые где-то хранятся, а это означает, что виртуальный адрес должен быть одинаковым для всех пользователей физической загрузки DLL. И ОС обычно не использует физический адрес. Он назначает виртуальный адрес области физической памяти, но это единственный случай, когда используется физический адрес. - person Mats Petersson; 11.02.2020