Udostępnij za pośrednictwem


Domeny aplikacji

Uwaga / Notatka

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, uważa się za bezpieczny dla typu. Możliwość weryfikacji kodu pod kątem bezpieczeństwa typów umożliwia wspólnemu środowisku uruchomieniowemu zapewnienie poziomu izolacji na równi z granicą procesu, przy znacznie mniejszych kosztach związanych z 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 / Notatka

    Nie można rozładować pojedynczych zestawów ani typów. Można odładować 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, który zawiera, należy załadować zestaw do domeny aplikacji. Uruchomienie typowej aplikacji powoduje załadowanie kilku zestawów do domeny aplikacji.

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

  • Jeśli zestaw jest ładowany jako neutralny dla domeny, wszystkie domeny aplikacji, które współużytkuje ten sam zestaw zabezpieczeń, mogą współużytkować ten sam kod skompilowany w trybie JIT, co zmniejsza ilość pamięci wymaganej przez aplikację. Jednak nigdy nie można zwolnić zestawu z procesu.

  • Jeśli zestaw nie jest załadowany neutralnie względem domeny, musi być kompilowane JIT w każdej domenie aplikacji, w której jest załadowany. Zestaw można jednak zwolnić z procesu, zwalniając wszystkie domeny aplikacji, w których jest ładowany.

Host środowiska uruchomieniowego określa, czy zestawy mają być ładowane jako neutralne dla domeny podczas ładowania środowiska uruchomieniowego do procesu. W przypadku aplikacji zarządzanych zastosuj LoaderOptimizationAttribute atrybut do metody punktu wejścia dla procesu i określ wartość ze skojarzonego LoaderOptimization wyliczenia. W przypadku niezarządzanych aplikacji hostujących środowisko uruchomieniowe języka wspólnego należy określić odpowiednią flagę podczas wywoływania funkcji CorBindToRuntimeEx.

Istnieją trzy opcje ładowania zestawów neutralnych dla domeny:

  • LoaderOptimization.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.

  • LoaderOptimization.MultiDomain ładuje wszystkie zbiory jako neutralne w kontekście domeny. Użyj tego ustawienia, jeśli w procesie istnieje wiele domen aplikacji, z których wszystkie uruchamiają ten sam kod.

  • LoaderOptimization.MultiDomainHost ładuje zestawy o silnych nazwach jako neutralne dla domeny, jeśli zostały zainstalowane w globalnej pamięci podręcznej składników. Inne zestawy są ładowane i kompilowane JIT oddzielnie dla każdej domeny aplikacji, w której są ładowane, i dlatego mogą być usunięte z procesu. To ustawienie należy użyć podczas uruchamiania więcej niż jednej aplikacji w tym samym procesie lub jeśli masz kombinację zestawów, które są współużytkowane przez wiele domen aplikacji i zestawów, które należy zwolnić z procesu.

Nie można współużytkować kodu skompilowanego w trybie JIT dla zestawów załadowanych do kontekstu ładowania za pomocą metody LoadFrom klasy Assembly, lub załadowanych z obrazów przy użyciu przeciążeń metody Load, które określają tablice bajtów.

Zestawy, które zostały skompilowane do kodu natywnego przy użyciu Ngen.exe (generatora obrazów natywnych), mogą być współdzielone między domenami aplikacji, jeśli za pierwszym razem są ładowane do procesu w sposób neutralny domenowo.

Skompilowany kod JIT dla zestawu, który zawiera punkt wejścia aplikacji, jest współużytkowany tylko wtedy, gdy wszystkie jego zależności mogą być współużytkowane.

Zestaw neutralny pod względem domeny może być kompilowany JIT więcej niż raz. Na przykład gdy zestawy przyznawania zabezpieczeń dwóch domen aplikacji są różne, nie mogą współużytkować tego samego kodu skompilowanego w trybie JIT. Jednak każda kopia zestawu skompilowanego JIT może być współdzielona z innymi domenami aplikacji, które mają ten sam zestaw uprawnień.

Jeśli zdecydujesz, czy zestawy mają być ładowane jako neutralne dla domeny, należy dokonać kompromisu między zmniejszeniem użycia pamięci a innymi czynnikami wydajności.

  • Dostęp do danych statycznych i metod jest wolniejszy w przypadku zestawów neutralnych dla domeny ze względu na potrzebę izolowania zestawów. Każda domena aplikacji, która uzyskuje dostęp do zestawu, musi mieć oddzielną kopię danych statycznych, aby zapobiec przekraczaniu granic domeny odwołań do obiektów w polach statycznych. W rezultacie środowisko uruchomieniowe zawiera dodatkową logikę kierującą obiekt wywołujący do odpowiedniej kopii danych statycznych lub metody. Ta dodatkowa logika spowalnia wywołanie.

  • Wszystkie zależności zestawu muszą być zlokalizowane i załadowane, gdy zestaw jest ładowany jako neutralny pod względem domeny, ponieważ zależność, której nie można załadować jako neutralnej pod względem domeny, uniemożliwia załadowanie zestawu jako neutralnego pod względem domeny.

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, które wątki działają w których domenach 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

Obiekt reprezentujący kulturę jest skojarzony 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 wynosi null, kultura zwracana przez tę właściwość jest skojarzona z wątkiem (i dlatego jest zwracana przez właściwości Thread.CurrentCulture 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

Domeny aplikacji są zwykle tworzone i manipulowane programowo przez hosty środowiska uruchomieniowego. Jednak czasami program aplikacji może również chcieć pracować z domenami aplikacji. Na przykład program aplikacji może załadować składnik aplikacji do domeny, aby móc zwolnić domenę (i składnik) bez konieczności zatrzymywania całej aplikacji.

Obiekt AppDomain to interfejs programistyczny do domen aplikacyjnych. Ta klasa zawiera metody tworzenia i zwalniania domen, tworzenia wystąpień typów w domenach oraz rejestrowania się na potrzeby różnych powiadomień, takich jak zwalnianie domeny aplikacji. W poniższej tabeli wymieniono powszechnie używane AppDomain metody.

Metoda AppDomain Opis
CreateDomain Tworzy nową domenę aplikacji. Zaleca się użycie przeciążenia tej metody, które określa obiekt AppDomainSetup. Jest to preferowany sposób ustawiania właściwości nowej domeny, takiej jak baza aplikacji lub katalog główny dla aplikacji; lokalizacja pliku konfiguracji dla domeny; i ścieżka wyszukiwania, która jest używana przez środowisko uruchomieniowe języka wspólnego do ładowania zestawów do domeny.
ExecuteAssembly i ExecuteAssemblyByName Uruchamia kompilację w kontekście domeny aplikacji. Jest to metoda instancyjna, więc może służyć do wykonywania kodu w innym obszarze aplikacji, do którego masz odwołanie.
CreateInstanceAndUnwrap Tworzy wystąpienie określonego typu w domenie aplikacji i zwraca serwer proxy. Użyj tej metody, aby uniknąć ładowania zestawu zawierającego utworzony typ do zestawu wywołującego.
Unload Wykonuje bezproblemowe zamykanie domeny. Aplikacja nie zostanie zwolniona z domeny, dopóki wszystkie uruchomione w niej wątki nie zostaną zatrzymane lub już jej nie opuszczą.

Uwaga / Notatka

Środowisko uruchomieniowe języka wspólnego nie obsługuje serializacji metod globalnych, dlatego delegatów nie można używać do wykonywania metod globalnych w innych domenach aplikacji.

Niezarządzane interfejsy opisane w specyfikacji interfejsów hostingu środowiska uruchomieniowego języka wspólnego zapewniają również dostęp do domen aplikacji. Hosty środowiska uruchomieniowego mogą używać interfejsów z niezarządzanego kodu w celu utworzenia i uzyskania dostępu do domen aplikacji w ramach 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 zmusza hosta środowiska uruchomieniowego do załadowania wszystkich zestawów w sposób nie neutralny dla domen, 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.

Ostrzeżenie

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ć, że wszystkie zestawy nie zostaną załadowane jako neutralne dla domeny dla usługi IISADMIN, można do wartości wielociągowej środowiska w kluczu HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\IISADMIN dodać COMPLUS_LoaderOptimization=1.

Key = HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\IISADMIN
Name = Environment
Type = REG_MULTI_SZ
Value (to append) = COMPLUS_LoaderOptimization=1

Zobacz także