Udostępnij za pośrednictwem


Domeny aplikacji

Uwaga

Ten artykuł jest specyficzny dla programu .NET Framework. Nie ma zastosowania do nowszych implementacji platformy .NET, w tym .NET 6 i nowszych wersji.

Systemy operacyjne i środowiska uruchomieniowe zwykle zapewniają pewną formę izolacji między aplikacjami. Na przykład system Windows używa procesów do izolowania aplikacji. Ta izolacja jest niezbędna do zapewnienia, że kod działający w jednej aplikacji nie może negatywnie wpłynąć na inne, niepowiązane aplikacje.

Domeny aplikacji zapewniają granicę izolacji na potrzeby zabezpieczeń, niezawodności i przechowywania wersji oraz zwalniania zestawów. Domeny aplikacji są zwykle tworzone przez hosty środowiska uruchomieniowego, które są odpowiedzialne za uruchamianie środowiska uruchomieniowego języka wspólnego przed uruchomieniem aplikacji.

Zalety izolowania aplikacji

W przeszłości granice procesów były używane do izolowania aplikacji działających na tym samym komputerze. Każda aplikacja jest ładowana do oddzielnego procesu, który izoluje aplikację od innych aplikacji uruchomionych na tym samym komputerze.

Aplikacje są izolowane, ponieważ adresy pamięci są względne pod względem procesów; wskaźnik pamięci przekazywany z jednego procesu do innego nie może być używany w żaden znaczący sposób w procesie docelowym. Ponadto nie można wykonywać bezpośrednich wywołań między dwoma procesami. Zamiast tego należy użyć serwerów proxy, które zapewniają poziom pośredni.

Kod zarządzany musi zostać przekazany przez proces weryfikacji, zanim będzie można go uruchomić (chyba że administrator udzielił uprawnień do pominięcia weryfikacji). Proces weryfikacji określa, czy kod może próbować uzyskać dostęp do nieprawidłowych adresów pamięci, czy wykonać inną akcję, która może spowodować, że proces, w którym działa, nie działa prawidłowo. Kod, który przechodzi test weryfikacyjny, jest mówi się, że jest bezpieczny dla typu. Możliwość weryfikacji kodu jako bezpiecznego dla typu umożliwia środowisko uruchomieniowe języka wspólnego zapewnienie tak dużego poziomu izolacji, jak granica procesu, przy znacznie niższych kosztach wydajności.

Domeny aplikacji zapewniają bezpieczniejszą i wszechstronną jednostkę przetwarzania, za pomocą którego środowisko uruchomieniowe języka wspólnego może zapewnić izolację między aplikacjami. W jednym procesie można uruchomić kilka domen aplikacji z tym samym poziomem izolacji, które istniałyby w oddzielnych procesach, ale bez ponoszenia dodatkowych obciążeń związanych z wykonywaniem wywołań między procesami lub przełączaniem między procesami. Możliwość uruchamiania wielu aplikacji w ramach jednego procesu znacznie zwiększa skalowalność serwera.

Izolowanie aplikacji jest również ważne w przypadku zabezpieczeń aplikacji. Na przykład można uruchamiać kontrolki z kilku aplikacji internetowych w jednym procesie przeglądarki w taki sposób, aby kontrolki nie mogły uzyskiwać dostępu do danych i zasobów.

Izolacja zapewniana przez domeny aplikacji ma następujące korzyści:

  • Błędy w jednej aplikacji nie mogą mieć wpływu na inne aplikacje. Ponieważ kod bezpieczny pod kątem typu nie może powodować błędów pamięci, użycie domen aplikacji gwarantuje, że kod działający w jednej domenie nie może mieć wpływu na inne aplikacje w procesie.

  • Poszczególne aplikacje można zatrzymać bez zatrzymywania całego procesu. Korzystanie z domen aplikacji umożliwia zwolnienie kodu uruchomionego w jednej aplikacji.

    Uwaga

    Nie można zwolnić pojedynczych zestawów ani typów. Można zwolnić tylko pełną domenę.

  • Kod uruchomiony w jednej aplikacji nie może bezpośrednio uzyskać dostępu do kodu lub zasobów z innej aplikacji. Środowisko uruchomieniowe języka wspólnego wymusza tę izolację, uniemożliwiając bezpośrednie wywołania między obiektami w różnych domenach aplikacji. Obiekty przekazywane między domenami są kopiowane lub uzyskiwane przez serwer proxy. Jeśli obiekt jest kopiowany, wywołanie obiektu jest lokalne. Oznacza to, że zarówno obiekt wywołujący, jak i obiekt, do którego się odwołujesz, znajdują się w tej samej domenie aplikacji. Jeśli dostęp do obiektu jest uzyskiwany za pośrednictwem serwera proxy, wywołanie obiektu jest zdalne. W takim przypadku obiekt wywołujący i obiekt, do których się odwołujesz, znajdują się w różnych domenach aplikacji. Wywołania między domenami używają tej samej infrastruktury wywołań zdalnych co wywołania między dwoma procesami lub między dwoma maszynami. W związku z tym metadane obiektu, do których odwołuje się odwołanie, muszą być dostępne dla obu domen aplikacji, aby umożliwić prawidłowe skompilowanie wywołania metody JIT. Jeśli domena wywołująca nie ma dostępu do metadanych wywoływanego obiektu, kompilacja może zakończyć się niepowodzeniem z wyjątkiem typu FileNotFoundException. Aby uzyskać więcej informacji, zobacz Remote Objects (Obiekty zdalne). Mechanizm określania sposobu uzyskiwania dostępu do obiektów między domenami jest określany przez obiekt . Aby uzyskać więcej informacji, zobacz System.MarshalByRefObject.

  • Zachowanie kodu jest ograniczone przez aplikację, w której jest uruchamiana. Innymi słowy domena aplikacji udostępnia ustawienia konfiguracji, takie jak zasady wersji aplikacji, lokalizację wszystkich zestawów zdalnych, do których uzyskuje dostęp, oraz informacje o miejscu lokalizowania zestawów załadowanych do domeny.

  • Uprawnienia przyznane kodowi mogą być kontrolowane przez domenę aplikacji, w której jest uruchomiony kod.

Domeny aplikacji i zestawy

W tej sekcji opisano relację między domenami aplikacji i zestawami. Aby można było wykonać kod zawarty w zestawie, należy go załadować do domeny aplikacji. Uruchomienie typowej aplikacji powoduje wczytanie kilku zestawów do domeny aplikacji.

Sposób ładowania zestawu określa, czy jego kod kompilowany dokładnie na czas (JIT) kod może być współużytkowany przez wiele domen aplikacji uczestniczących w procesie oraz czy zestaw można zwolnić z pamięci procesu.

  • Jeśli zestaw został załadowany jako neutralny dla domen, wszystkie domeny aplikacji mające ten sam zestaw uprawnień zabezpieczeń mogą współużytkować ten sam kod skompilowany dokładnie na czas, co zmniejsza zapotrzebowanie aplikacji na pamięć. Jednak zestawu nigdy nie można zwolnić z pamięci procesu.

  • Jeśli zestaw nie jest wczytywany jako neutralny dla domen, musi być kompilowany dokładnie na czas w każdej domenie aplikacji, do której jest ładowany. Zestaw można jednak zwolnić z pamięci procesu poprzez zwolnienie wszystkich domen aplikacji, w których został załadowany.

Host środowiska uruchomieniowego określa, czy podczas ładowania środowiska uruchomieniowego do procesu ma ładować zestawy jako neutralne dla domen. W przypadku zarządzanych aplikacji należy zastosować atrybut LoaderOptimizationAttribute do metody punktu wejścia procesu oraz określić wartość z powiązanego wyliczenia LoaderOptimization. W przypadku niezarządzanych aplikacji hostujących środowisko uruchomieniowe języka wspólnego określ odpowiednią flagę podczas wywoływania metody funkcji CorBindToRuntimeEx.

Istnieją trzy sposoby wczytywania zestawów jako neutralnych dla domen:

  • LoaderOptimization.SingleDomain nie ładuje zestawów jako neutralnych dla domen, z wyjątkiem zestawu Mscorlib, który zawsze jest ładowany jako neutralny dla domen. To ustawienie jest nazywane pojedynczą domeną, ponieważ jest często używane, gdy host uruchamia tylko jedną aplikację w procesie.

  • LoaderOptimization.MultiDomain wczytuje wszystkie zestawy jako neutralne dla domen. Tego ustawienia należy używać, gdy w procesie istnieje wiele domen aplikacji uruchamiających ten sam kod.

  • LoaderOptimization.MultiDomainHost ładuje zestawy o silnych nazwach jako neutralne dla domen, jeśli zestawy i ich obiekty zależne zostały zainstalowane w globalnej pamięć podręcznej zestawów. Inne zestawy są wczytywane i kompilowane dokładnie na czas osobno dla każdej domeny aplikacji, do której zostały wczytane, dlatego można je zwolnić z pamięci procesu. Ustawienie należy stosować w przypadku, gdy w tym samym procesie działa więcej niż jedna aplikacja w tym samym procesie albo jeśli istnieje zbiór zestawów współużytkowanych przez wiele domen aplikacji oraz zestawów, które muszą być zwalniane z pamięci procesu.

Kod kompilowany dokładnie na czas nie może być współużytkowany przez zestawy ładowane w kontekście ich źródła pochodzenia za pomocą metody LoadFrom klasy Assembly ani ładowane z obrazów przy użyciu przeciążeń metody Load, która określa tablice bajtowe.

Zestawy, które zostały skompilowane do kodu natywnego przy użyciu Ngen.exe (generatora obrazów natywnych) mogą być współużytkowane między domenami aplikacji, jeśli są ładowane neutralne pod względem domeny po raz pierwszy są ładowane do procesu.

Kod zestawu kompilowany dokładnie na czas, który zawiera punkt wejścia aplikacji, jest udostępniany tylko wtedy, gdy można współużytkować jego wszystkie zależności.

Zestawy neutralny dla domen można kompilować dokładnie na czas więcej niż jeden raz. Na przykład gdy dwie domeny aplikacji mają różne zestawy uprawnień zabezpieczeń, nie mogą używać tego samego kodu kompilowanego dokładnie na czas. Jednak każdą kopię zestawu kompilowanego dokładnie na czas można udostępnić innym domenom aplikacji, które mają taki sam zestaw uprawnień.

Decydując, czy zestawy mają być wczytywane jako neutralne dla domen, należy wziąć pod uwagę kompromis między ograniczeniem użycia pamięci a innymi czynnikami wydajnościowymi.

  • Zestawy neutralne dla domen mają wolniejszy dostęp do statycznych danych i metod, ponieważ zestawy trzeba izolować. Każda domena aplikacji uzyskująca dostęp do zestawu musi mieć oddzielną kopię danych statycznych, aby uniemożliwić odwołaniom w statycznych polach przekraczanie granic domeny. W rezultacie środowisko uruchomieniowe zawiera dodatkową logikę, która przekierowuje obiekt wywołujący do odpowiedniej kopii statycznych danych lub metody. Ta dodatkowa logika spowalnia wywołanie.

  • Gdy zestaw jest wczytywany jako niezależny od domen, muszą być odnajdowane i ładowane jego wszystkie zależności, ponieważ zależność, której nie można wczytać jako neutralnej dla domen, uniemożliwia wczytanie w ten sposób całego zestawu.

Domeny aplikacji i wątki

Domena aplikacji stanowi granicę izolacji na potrzeby zabezpieczeń, przechowywania wersji, niezawodności i zwalniania kodu zarządzanego. Wątek to konstrukcja systemu operacyjnego używana przez środowisko uruchomieniowe języka wspólnego do wykonywania kodu. W czasie wykonywania cały kod zarządzany jest ładowany do domeny aplikacji i jest uruchamiany przez co najmniej jeden zarządzany wątek.

Nie istnieje korelacja jeden do jednego między domenami aplikacji i wątkami. Kilka wątków może być wykonywanych w jednej domenie aplikacji w danym momencie, a określony wątek nie jest ograniczony do jednej domeny aplikacji. Oznacza to, że wątki mogą przekraczać granice domeny aplikacji; nowy wątek nie jest tworzony dla każdej domeny aplikacji.

W dowolnym momencie każdy wątek jest wykonywany w domenie aplikacji. Zero, jeden lub wiele wątków może być wykonywanych w dowolnej domenie aplikacji. Środowisko uruchomieniowe śledzi, w których wątkach działają domeny aplikacji. Możesz zlokalizować domenę, w której wątek jest wykonywany w dowolnym momencie, wywołując metodę Thread.GetDomain .

Domeny i kultury aplikacji

Kultura, która jest reprezentowana CultureInfo przez obiekt, jest skojarzona z wątkami. Możesz pobrać kulturę skojarzona z aktualnie wykonywanym wątkiem przy użyciu CultureInfo.CurrentCulture właściwości , a także pobrać lub ustawić kulturę skojarzona z aktualnie wykonywanym wątkiem przy użyciu Thread.CurrentCulture właściwości . Jeśli kultura skojarzona z wątkiem została jawnie ustawiona przy użyciu Thread.CurrentCulture właściwości , będzie ona nadal skojarzona z tym wątkiem, gdy wątek przekracza granice domeny aplikacji. W przeciwnym razie kultura skojarzona z wątkiem w danym momencie jest określana przez wartość CultureInfo.DefaultThreadCurrentCulture właściwości w domenie aplikacji, w której jest wykonywany wątek:

  • Jeśli wartość właściwości nie nullma wartości , kultura zwracana przez właściwość jest skojarzona z wątkiem (i dlatego zwracana przez Thread.CurrentCulture właściwości i CultureInfo.CurrentCulture ).

  • Jeśli wartość właściwości to null, bieżąca kultura systemowa jest skojarzona z wątkiem.

Programowanie z domenami aplikacji

Zazwyczaj domeny aplikacji tworzy się i wykonuje na nich operacje programowo za pomocą hostów środowiska uruchomieniowego. Czasami jednak z domenami aplikacji chcą pracować programy. Na przykład program może wczytywać składnik aplikacji do domeny, aby umożliwić zwolnienie domeny (i składnika) z pamięci bez konieczności zatrzymywania całej aplikacji.

Jest AppDomain to interfejs programowy do domen aplikacji. Zawiera ona metody tworzenia domen i zwalniania ich z pamięci, tworzenia wystąpień typów w domenach oraz rejestrowania w celu otrzymywania różnych powiadomień, np. o zwalnianiu domen aplikacji z pamięci. W poniższej tabeli wymieniono powszechnie używane AppDomain metody.

Metoda klasy AppDomain opis
CreateDomain Tworzenie nowej domeny aplikacji. Zaleca się używanie przeciążenia tej metody, które określa obiekt AppDomainSetup. Jest to preferowany sposób konfigurowania właściwości nowej domeny, takich jak baza aplikacji czy główny katalog aplikacji, lokalizacja pliku konfiguracji domeny oraz ścieżka wyszukiwania, z której środowisko uruchomieniowe języka wspólnego ma ładować zestawy do domeny.
ExecuteAssembly i ExecuteAssemblyByName Wykonywanie zestawu w domenie aplikacji. To jest metoda wystąpienia, dlatego może służyć do wykonywania kodu w innej domenie aplikacji, do której prowadzi odwołanie.
CreateInstanceAndUnwrap Tworzenie wystąpienie wskazanego typu w domenie aplikacji oraz zwracanie danych serwera proxy. Ta metoda pozwala uniknąć wczytywania zestawu zawierającego utworzony typ do wywoływanego zestawu.
Unload Uporządkowanie wyłączanie domeny. Domena aplikacji zostanie zwolniona z pamięci dopiero wtedy, gdy wszystkie wątki uruchomione w domenie zostaną zatrzymane lub przestaną być obecne w domenie.

Uwaga

Środowisko uruchomieniowe języka wspólnego nie obsługuje serializacji metod globalnych, dlatego delegaci nie mogą wykonywać globalnych metod w innych domenach aplikacji.

Dostęp do domen aplikacji zapewniają również niezarządzane interfejsy opisane w specyfikacji interfejsów hostujących środowiska uruchomieniowego języka wspólnego. Hosty środowiska uruchomieniowego mogą za pomocą interfejsów z niezarządzanego kodu tworzyć domeny aplikacji i uzyskiwać do nich dostęp wewnątrz procesu.

Zmienna środowiskowa COMPLUS_LoaderOptimization

Zmienna środowiskowa, która ustawia domyślne zasady optymalizacji modułu ładującego aplikacji wykonywalnej.

Składnia

COMPLUS_LoaderOptimization = 1

Uwagi

Typowa aplikacja ładuje kilka zestawów do domeny aplikacji, zanim będzie można wykonać kod, który zawiera.

Sposób ładowania zestawu określa, czy jego skompilowany kod just in time (JIT) może być współużytkowany przez wiele domen aplikacji w procesie.

  • Jeśli zestaw jest ładowany jako neutralny dla domeny, wszystkie domeny aplikacji współużytkujące ten sam zestaw zabezpieczeń mogą współużytkować ten sam kod skompilowany w trybie JIT. Zmniejsza to ilość pamięci wymaganej przez aplikację.

  • Jeśli zestaw nie jest załadowany neutralnie dla domeny, musi być skompilowany JIT w każdej domenie aplikacji, w której jest ładowany, a moduł ładujący nie może współużytkować zasobów wewnętrznych w domenach aplikacji.

Po ustawieniu wartości 1 flaga środowiska COMPLUS_LoaderOptimization wymusza, aby host środowiska uruchomieniowego załadował wszystkie zestawy w sposób neutralny dla domeny znany jako SingleDomain. SingleDomain nie ładuje żadnych zestawów jako neutralnych dla domeny, z wyjątkiem biblioteki Mscorlib, która jest zawsze ładowana jako neutralna dla domeny. To ustawienie jest nazywane pojedynczą domeną, ponieważ jest często używane, gdy host uruchamia tylko jedną aplikację w procesie.

Uwaga

Flaga środowiska COMPLUS_LoaderOptimization została zaprojektowana do użycia w scenariuszach diagnostycznych i testowych. Włączenie flagi może spowodować poważne spowolnienie i zwiększenie użycia pamięci.

Przykład kodu

Aby wymusić, aby wszystkie zestawy nie zostały załadowane jako neutralne dla domeny dla usługi IISADMIN, można dołączyć COMPLUS_LoaderOptimization=1 wartość wielociągową środowiska w kluczu 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

Zobacz też