Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Замечание
Эта статья связана с .NET Framework. Он не применяется к более новым реализациям .NET, включая .NET 6 и более поздние версии.
Операционные системы и среды выполнения обычно обеспечивают некоторую форму изоляции между приложениями. Например, Windows использует процессы для изоляции приложений. Эта изоляция необходима, чтобы убедиться, что код, выполняемый в одном приложении, не может негативно повлиять на другие, не связанные приложения.
Домены приложений предоставляют границу изоляции для безопасности, надежности и управления версиями, а также для выгрузки сборок. Домены приложений обычно создаются узлами среды выполнения, которые отвечают за загрузку среды CLR перед запуском приложения.
Преимущества изоляции приложений
Исторически границы процессов использовались для изоляции приложений, работающих на одном компьютере. Каждое приложение загружается в отдельный процесс, который изолирует приложение от других приложений, работающих на том же компьютере.
Приложения изолированы, так как адреса памяти являются относительными к процессу; Указатель памяти, передаваемый из одного процесса в другой, не может использоваться каким-либо значимым способом в целевом процессе. Кроме того, нельзя выполнять прямые вызовы между двумя процессами. Вместо этого необходимо использовать прокси, которые обеспечивают уровень косвенности.
Управляемый код необходимо передать через процесс проверки перед его запуском (если администратор не предоставил разрешение пропустить проверку). Процесс проверки определяет, может ли код попытаться получить доступ к недопустимым адресам памяти или выполнить какое-либо другое действие, которое может привести к тому, что процесс, в котором он работает, не работает должным образом. Код, который проходит проверку, считается типобезопасным. Возможность проверки кода как типобезопасного позволяет среде CLR обеспечить такой уровень изоляции, как граница процесса, при гораздо более низкой стоимости производительности.
Домены приложений обеспечивают более безопасную и универсальную единицу обработки, которую среда CLR может использовать для изоляции между приложениями. Вы можете запускать несколько доменов приложений в одном процессе с одинаковым уровнем изоляции, который будет существовать в отдельных процессах, но без дополнительных затрат на выполнение вызовов между процессами или переключение между процессами. Возможность запуска нескольких приложений в одном процессе значительно увеличивает масштабируемость сервера.
Изоляция приложений также важна для безопасности приложений. Например, можно запускать элементы управления из нескольких веб-приложений в одном процессе браузера таким образом, чтобы элементы управления не могли получать доступ к данным и ресурсам друг друга.
Изоляция, предоставляемая доменами приложений, имеет следующие преимущества:
Ошибки в одном приложении не могут повлиять на другие приложения. Так как типобезопасный код не может привести к сбоям памяти, использование доменов приложений гарантирует, что код, выполняемый в одном домене, не может повлиять на другие приложения в процессе.
Отдельные приложения можно остановить без остановки всего процесса. Использование доменов приложений позволяет выгрузить код, выполняемый в одном приложении.
Замечание
Вы не можете выгрузить отдельные сборки или типы. Можно выгрузить только полный домен.
Код, выполняемый в одном приложении, не может напрямую получить доступ к коду или ресурсам из другого приложения. Среда CLR применяет эту изоляцию, предотвращая прямые вызовы между объектами в разных доменах приложений. Объекты, проходящие между доменами, копируются или доступны через прокси. Если объект копируется, вызов объекта является локальным. То есть вызывающий объект и объект находятся в одном домене приложения. Если доступ к объекту осуществляется через прокси-сервер, вызов объекта является удаленным. В этом случае вызывающий объект и объект, на который ссылается, находятся в разных доменах приложений. Вызовы между доменами используют ту же инфраструктуру удаленного вызова, что и вызовы между двумя процессами или между двумя компьютерами. Таким образом, метаданные для объекта, на который ссылается ссылка, должны быть доступны обоим доменам приложений, чтобы разрешить вызов метода правильно скомпилировать JIT. Если вызывающий домен не имеет доступа к метаданным вызываемого объекта, компиляция может завершиться ошибкой исключения типа FileNotFoundException. Дополнительные сведения см. в разделе "Удаленные объекты". Механизм определения доступа к объектам между доменами определяется объектом. Дополнительные сведения см. в разделе System.MarshalByRefObject.
Поведение кода определяется приложением, в котором он выполняется. Другими словами, домен приложения предоставляет такие параметры конфигурации, как политики версий приложения, расположение любых удаленных сборок, к которым он обращается, и сведения о том, где находить сборки, загруженные в домен.
Предоставленными коду разрешениями можно управлять с помощью домена приложения, в котором выполняется этот код.
Домены приложений и сборки
В этом разделе описывается связь между доменами приложений и сборками. Перед выполнением кода, содержащего его, необходимо загрузить сборку в домен приложения. Выполнение типичного приложения приводит к загрузке нескольких сборок в домен приложения.
Способ загрузки сборки определяет, может ли её JIT-код быть использован множеством доменов приложений в процессе и можно ли удалить сборку из процесса.
Если сборка загружается нейтрально к доменам, все домены приложений, использующие один и тот же набор прав безопасности, могут совместно использовать один и тот же JIT-компилированный код, что сокращает объем памяти, необходимый для приложения. Однако сборка никогда не может быть выгружена из процесса.
Если сборка не загружается нейтрально к домену, её необходимо компилировать JIT в каждом домене приложения, в котором она загружается. Однако сборку можно выгрузить из процесса, выгрузив все домены приложений, в которых она загружается.
Хост среды выполнения определяет, следует ли загружать сборки как нейтральные к домену, когда среда выполнения загружается в процесс. Для управляемых приложений примените LoaderOptimizationAttribute атрибут к методу точки входа для процесса и укажите значение из связанного LoaderOptimization перечисления. Для неуправляемых приложений, которые размещают общую языковую среду выполнения (CLR), укажите соответствующий флаг при вызове метода функции CorBindToRuntimeEx.
Существует три варианта загрузки доменно-нейтральных сборок.
LoaderOptimization.SingleDomain не загружает сборки как нейтрализуемые доменом, кроме Mscorlib, которая всегда загружается в качестве нейтральной домена. Этот параметр называется одним доменом, так как он обычно используется при запуске узла только одного приложения в процессе.
LoaderOptimization.MultiDomain загружает все сборки как домен-независимые. Используйте этот параметр, если в процессе есть несколько доменов приложений, все из которых выполняют один и тот же код.
LoaderOptimization.MultiDomainHost загружает сборки с сильными именами как нейтральные к домену, если они и все их зависимости были установлены в глобальном кэше сборок. Другие сборки загружаются и проходят JIT-компиляцию отдельно для каждого домена приложения, в котором они загружаются, и поэтому могут быть удалены из процесса. Используйте этот параметр при выполнении нескольких приложений в одном процессе или при наличии сочетания сборок, совместно используемых многими доменами приложений и сборками, которые необходимо выгрузить из процесса.
Скомпилированный JIT-код нельзя совместно использовать для сборок, загруженных в контекст load-from, с помощью метода LoadFrom класса Assembly или загруженных из образов с использованием перегрузок метода Load, указывающих массивы байтов.
Сборки, скомпилированные в машинный код с помощью Ngen.exe (генератора собственных образов), могут быть совместно использованы между доменами приложений, если они загружены в процесс в нейтральном отношении к домену при первой загрузке.
Скомпилированный JIT-код для сборки, содержащей точку входа приложения, предоставляется только в том случае, если все его зависимости могут быть общими.
Независимая от домена сборка может быть скомпилирована несколько раз. Например, если наборы предоставления безопасности двух доменов приложений отличаются, они не могут совместно использовать один и тот же скомпилированный JIT-код. Однако каждая копия скомпилированной JIT-сборки может быть использована другими доменами приложений с одинаковым набором разрешений.
При выборе того, следует ли загружать сборки как доменные нейтральные, необходимо сделать компромисс между сокращением использования памяти и другими факторами производительности.
Доступ к статическим данным и методам медленнее для доменно-нейтральных сборок из-за необходимости изоляции сборок. Каждый домен приложения, обращаюющийся к сборке, должен иметь отдельную копию статических данных, чтобы предотвратить ссылки на объекты в статических полях от пересечения границ домена. В результате среда выполнения содержит дополнительную логику для направления вызывающего объекта в соответствующую копию статических данных или метода. Эта дополнительная логика замедляет вызов.
Все зависимости сборки должны быть найдены и загружены при загрузке сборки в режиме нейтрального домена, поскольку зависимость, которая не может быть загружена в нейтральном к домену режиме, препятствует загрузке сборки в этом режиме.
Домены приложений и потоки
Домен приложения формирует границу изоляции для безопасности, управления версиями, надежности и выгрузки управляемого кода. Поток — это конструкция операционной системы, используемая общеязыковой средой выполнения (CLR) для выполнения кода. Во время выполнения весь управляемый код загружается в домен приложения и выполняется одним или несколькими управляемыми потоками.
Между доменами приложений и потоками отсутствует однозначная связь. Несколько потоков могут выполняться в одном домене приложения в любое время, и определенный поток не ограничивается одним доменом приложения. То есть потоки свободно пересекают границы домена приложения; Новый поток не создается для каждого домена приложения.
В любое время каждый поток выполняется в домене приложения. Ноль, один или несколько потоков могут выполняться в любом заданном домене приложения. Среда выполнения отслеживает, какие потоки работают в каких доменах приложений. Вы можете найти домен, в котором поток выполняется в любое время, вызвав Thread.GetDomain метод.
Домены приложений и культуры
Культура, представленная объектом CultureInfo, связана с потоками. Вы можете получить язык и региональные параметры, связанные с текущим выполнением потока с помощью CultureInfo.CurrentCulture свойства, и вы можете получить или задать язык и региональные параметры, связанные с текущим выполняемым потоком с помощью Thread.CurrentCulture свойства. Если язык и региональные параметры, связанные с потоком, явно заданы с помощью Thread.CurrentCulture свойства, они продолжают быть связаны с этим потоком, когда поток пересекает границы домена приложения. В противном случае культура, связанная с потоком в любой момент времени, определяется значением свойства CultureInfo.DefaultThreadCurrentCulture в домене приложения, в котором выполняется поток.
Если значение свойства не
null, культура, возвращаемая свойством, связана с потоком (и поэтому она возвращается свойствами Thread.CurrentCulture и CultureInfo.CurrentCulture).Если значение свойства равно
null, к данному потоку привязывается текущая культура системы.
Программирование с помощью доменов приложений
Домены приложений обычно создаются и управляются программными средствами узлами среды выполнения. Однако иногда программа приложения может также работать с доменами приложений. Например, программа приложения может загрузить компонент приложения в домен, чтобы выгрузить домен (и компонент) без остановки всего приложения.
Это AppDomain программный интерфейс для доменов приложений. Этот класс включает методы для создания и выгрузки доменов, создания экземпляров типов в доменах и регистрации для различных уведомлений, таких как выгрузка домена приложения. В следующей таблице перечислены часто используемые AppDomain методы.
| Метод AppDomain | Описание |
|---|---|
| CreateDomain | Создает новый домен приложения. Рекомендуется использовать перегрузку этого метода, которая указывает на объект AppDomainSetup. Это предпочтительный способ задать свойства нового домена, например базу приложения или корневой каталог для приложения; расположение файла конфигурации для домена; и путь поиска, используемый средой CLR для загрузки сборок в домен. |
| ExecuteAssembly и ExecuteAssemblyByName. | Выполняет сборку в домене приложения. Это метод экземпляра, поэтому его можно использовать для выполнения кода в другом домене приложения, на который у вас есть ссылка. |
| CreateInstanceAndUnwrap | Создает экземпляр указанного типа в домене приложения и возвращает прокси-сервер. Используйте этот метод, чтобы избежать загрузки сборки, содержащей созданный тип в вызывающую сборку. |
| Unload | Выполняет безопасное завершение домена. Домен приложения не выгружается до тех пор, пока все потоки, работающие в домене, либо прекращают выполнение, либо больше не находятся в домене. |
Замечание
Среда CLR не поддерживает сериализацию глобальных методов, поэтому делегаты не могут использоваться для выполнения глобальных методов в других доменах приложений.
Неуправляемые интерфейсы, описанные в Спецификации интерфейсов размещения среды выполнения общего языка, также предоставляют доступ к доменам приложений. Узлы среды выполнения могут использовать интерфейсы из неуправляемого кода для создания и получения доступа к доменам приложения в процессе.
Переменная среды COMPLUS_LoaderOptimization
Переменная среды, которая задает политику оптимизации загрузчика по умолчанию исполняемого приложения.
Синтаксис
COMPLUS_LoaderOptimization = 1
Замечания
Обычное приложение загружает несколько сборок в домен приложения перед выполнением кода.
Способ загрузки сборки определяет, может ли ее JIT-код быть использован разными доменами приложений в процессе.
Если сборка загружается нейтрально к домену, все домены приложений, которые используют одинаковый набор безопасности, могут использовать один и тот же JIT-скомпилированный код. Это сокращает объем памяти, необходимый приложению.
Если сборка не загружается в домене с нейтральным отношением, она должна быть скомпилирована JIT в каждом домене приложения, где она загружается, и загрузчик не должен делиться внутренними ресурсами между доменами приложений.
Если задано значение 1, флаг среды COMPLUS_LoaderOptimization заставляет узел среды выполнения загружать все сборки в режиме, не нейтральном для домена, известном как SingleDomain. SingleDomain не загружает сборки как нейтральные для домена, кроме Mscorlib, которая всегда загружается нейтральной для домена. Этот параметр называется одним доменом, так как он обычно используется при запуске узла только одного приложения в процессе.
Осторожность
Флаг среды COMPLUS_LoaderOptimization предназначен для использования в сценариях диагностики и тестирования. Включение флага может привести к серьезному замедлению и увеличению использования памяти.
Пример кода
Чтобы принудительно все сборки не загружались как доменно-нейтральные для службы IISADMIN, можно достичь этого путем добавления COMPLUS_LoaderOptimization=1 в многострочное значение среды в ключе HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\IISADMIN.
Key = HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\IISADMIN
Name = Environment
Type = REG_MULTI_SZ
Value (to append) = COMPLUS_LoaderOptimization=1