Programdomäner

Kommentar

Den här artikeln är specifik för .NET Framework. Det gäller inte för nyare implementeringar av .NET, inklusive .NET 6 och senare versioner.

Operativsystem och körningsmiljöer ger vanligtvis någon form av isolering mellan program. Windows använder till exempel processer för att isolera program. Den här isoleringen är nödvändig för att säkerställa att kod som körs i ett program inte kan påverka andra, orelaterade program negativt.

Programdomäner ger en isoleringsgräns för säkerhet, tillförlitlighet och versionshantering samt för att ta bort sammansättningar. Programdomäner skapas vanligtvis av runtime-värdar, som ansvarar för att starta den vanliga språkkörningen innan ett program körs.

Fördelarna med att isolera program

Tidigare har processgränser använts för att isolera program som körs på samma dator. Varje program läses in i en separat process som isolerar programmet från andra program som körs på samma dator.

Programmen isoleras eftersom minnesadresserna är processrelativa. En minnespekare som skickas från en process till en annan kan inte användas på något meningsfullt sätt i målprocessen. Dessutom kan du inte göra direkta anrop mellan två processer. I stället måste du använda proxyservrar som ger en indirekt nivå.

Hanterad kod måste skickas genom en verifieringsprocess innan den kan köras (såvida inte administratören har beviljat behörighet att hoppa över verifieringen). Verifieringsprocessen avgör om koden kan försöka komma åt ogiltiga minnesadresser eller utföra någon annan åtgärd som kan leda till att processen där den körs inte fungerar korrekt. Kod som klarar verifieringstestet sägs vara typsäker. Möjligheten att verifiera kod som typsäker gör att den vanliga språkkörningen kan ge en lika bra isoleringsnivå som processgränsen, till en mycket lägre prestandakostnad.

Programdomäner ger en säkrare och mer mångsidig bearbetningsenhet som den gemensamma språkkörningen kan använda för att tillhandahålla isolering mellan program. Du kan köra flera programdomäner i en enda process med samma isoleringsnivå som skulle finnas i separata processer, men utan att medföra extra kostnader för att göra korsprocessanrop eller växla mellan processer. Möjligheten att köra flera program i en enda process ökar avsevärt serverns skalbarhet.

Isolera program är också viktigt för programsäkerhet. Du kan till exempel köra kontroller från flera webbprogram i en enda webbläsarprocess på ett sådant sätt att kontrollerna inte kan komma åt varandras data och resurser.

Isoleringen som tillhandahålls av programdomäner har följande fördelar:

  • Fel i ett program kan inte påverka andra program. Eftersom typsäker kod inte kan orsaka minnesfel säkerställer användning av programdomäner att kod som körs i en domän inte kan påverka andra program i processen.

  • Enskilda program kan stoppas utan att hela processen stoppas. Med hjälp av programdomäner kan du ta bort koden som körs i ett enda program.

    Kommentar

    Du kan inte ta bort enskilda sammansättningar eller typer. Endast en fullständig domän kan tas bort.

  • Kod som körs i ett program kan inte direkt komma åt kod eller resurser från ett annat program. Den vanliga språkkörningen framtvingar den här isoleringen genom att förhindra direkta anrop mellan objekt i olika programdomäner. Objekt som skickas mellan domäner kopieras eller nås av proxy. Om objektet kopieras är anropet till objektet lokalt. Det vill säga att både anroparen och objektet som refereras finns i samma programdomän. Om objektet nås via en proxyserver är anropet till objektet fjärranslutet. I det här fallet finns anroparen och objektet som refereras till i olika programdomäner. Anrop mellan domäner använder samma fjärranropsinfrastruktur som anrop mellan två processer eller mellan två datorer. Därför måste metadata för objektet som refereras vara tillgängliga för båda programdomänerna för att metodanropet ska kunna jit-kompileras korrekt. Om den anropande domänen inte har åtkomst till metadata för objektet som anropas kan kompilering misslyckas med ett undantag av typen FileNotFoundException. Mer information finns i Fjärrobjekt. Mekanismen för att avgöra hur objekt kan nås mellan domäner bestäms av objektet. Mer information finns i System.MarshalByRefObject.

  • Beteendet för kod begränsas av det program där den körs. Med andra ord tillhandahåller programdomänen konfigurationsinställningar som principer för programversion, platsen för alla fjärrsammansättningar som den kommer åt och information om var du hittar sammansättningar som läses in i domänen.

  • Behörigheter som beviljas för kod kan styras av programdomänen där koden körs.

Programdomäner och sammansättningar

I det här avsnittet beskrivs relationen mellan programdomäner och sammansättningar. Du måste läsa in en sammansättning i en programdomän innan du kan köra koden som den innehåller. Om du kör ett typiskt program läses flera sammansättningar in i en programdomän.

Hur en sammansättning läses in avgör om dess jit-kompilerade kod (just-in-time) kan delas av flera programdomäner i processen och om sammansättningen kan tas bort från processen.

  • Om en sammansättning läses in domänneutral kan alla programdomäner som delar samma säkerhetsbeviljande uppsättning dela samma JIT-kompilerade kod, vilket minskar det minne som krävs av programmet. Sammansättningen kan dock aldrig tas bort från processen.

  • Om en sammansättning inte läses in domänneutral måste den vara JIT-kompilerad i alla programdomäner där den läses in. Sammansättningen kan dock tas bort från processen genom att ta bort alla programdomäner där den läses in.

Körningsvärden avgör om sammansättningar ska läsas in som domänneutrala när körningen läses in i en process. För hanterade program tillämpar du LoaderOptimizationAttribute attributet på startpunktsmetoden för processen och anger ett värde från den associerade LoaderOptimization uppräkningen. För ohanterade program som är värdar för den vanliga språkkörningen anger du lämplig flagga när du anropar metoden CorBindToRuntimeEx Function .

Det finns tre alternativ för att läsa in domänneutrala sammansättningar:

  • LoaderOptimization.SingleDomain läser in inga sammansättningar som domänneutrala, förutom Mscorlib, som alltid läses in domänneutralt. Den här inställningen kallas enkel domän eftersom den ofta används när värden bara kör ett enda program i processen.

  • LoaderOptimization.MultiDomain läser in alla sammansättningar som domänneutrala. Använd den här inställningen när det finns flera programdomäner i processen, som alla kör samma kod.

  • LoaderOptimization.MultiDomainHost läser in starkt namngivna sammansättningar som domänneutrala, om de och alla deras beroenden har installerats i den globala sammansättningscacheminnet. Andra sammansättningar läses in och JIT-kompileras separat för varje programdomän där de läses in och kan därför tas bort från processen. Använd den här inställningen när du kör fler än ett program i samma process, eller om du har en blandning av sammansättningar som delas av många programdomäner och sammansättningar som måste tas bort från processen.

JIT-kompilerad kod kan inte delas för sammansättningar som läses in i inläsningskontexten LoadFrom , med hjälp av Assembly -klassens metod, eller läsas in från bilder med hjälp av överlagringar av metoden Load som anger bytematriser.

Sammansättningar som har kompilerats till intern kod med hjälp av Ngen.exe (inbyggd avbildningsgenerator) kan delas mellan programdomäner, om de läses in domänneutrala första gången de läses in i en process.

JIT-kompilerad kod för sammansättningen som innehåller programmets startpunkt delas endast om alla dess beroenden kan delas.

En domänneutral sammansättning kan JIT-kompileras mer än en gång. När säkerhetsbeviljande uppsättningar för två programdomäner är olika kan de till exempel inte dela samma JIT-kompilerade kod. Varje kopia av den JIT-kompilerade sammansättningen kan dock delas med andra programdomäner som har samma beviljandeuppsättning.

När du bestämmer dig för att läsa in sammansättningar som domänneutrala måste du göra en kompromiss mellan att minska minnesanvändningen och andra prestandafaktorer.

  • Åtkomsten till statiska data och metoder är långsammare för domänneutrala sammansättningar på grund av behovet av att isolera sammansättningar. Varje programdomän som kommer åt sammansättningen måste ha en separat kopia av statiska data för att förhindra att referenser till objekt i statiska fält korsar domängränserna. Därför innehåller körningen ytterligare logik för att dirigera en anropare till rätt kopia av statiska data eller -metoden. Den här extra logiken gör anropet långsammare.

  • Alla beroenden för en sammansättning måste finnas och läsas in när sammansättningen läses in domänneutralt, eftersom ett beroende som inte kan läsas in domänneutralt hindrar sammansättningen från att läsas in domänneutral.

Programdomäner och trådar

En programdomän utgör en isoleringsgräns för säkerhet, versionshantering, tillförlitlighet och avlastning av hanterad kod. En tråd är operativsystemets konstruktion som används av den vanliga språkkörningen för att köra kod. Vid körning läses all hanterad kod in i en programdomän och körs av en eller flera hanterade trådar.

Det finns ingen en-till-en-korrelation mellan programdomäner och trådar. Flera trådar kan köras i en enda programdomän vid en viss tidpunkt och en viss tråd är inte begränsad till en enda programdomän. Det vill: trådar är fria att korsa gränserna för programdomäner. en ny tråd skapas inte för varje programdomän.

Vid en viss tidpunkt körs varje tråd i en programdomän. Noll, en eller flera trådar kan köras i en viss programdomän. Körningen håller reda på vilka trådar som körs i vilka programdomäner. Du kan hitta domänen där en tråd körs när som helst genom att anropa Thread.GetDomain metoden.

Programdomäner och kulturer

Kultur, som representeras av ett CultureInfo objekt, är associerad med trådar. Du kan hämta den kultur som är associerad med den aktuella körningstråden CultureInfo.CurrentCulture med hjälp av egenskapen och du kan hämta eller ange den kultur som är associerad med den tråd som körs just nu med hjälp Thread.CurrentCulture av egenskapen . Om den kultur som är associerad med en tråd uttryckligen har angetts med hjälp Thread.CurrentCulture av egenskapen, fortsätter den att associeras med den tråden när tråden korsar gränserna för programdomänen. Annars bestäms kulturen som är associerad med tråden vid en viss tidpunkt av CultureInfo.DefaultThreadCurrentCulture värdet för egenskapen i programdomänen där tråden körs:

  • Om värdet för egenskapen inte nullär associeras kulturen som returneras av egenskapen med tråden (och returneras därför av Thread.CurrentCulture egenskaperna och CultureInfo.CurrentCulture ).

  • Om värdet för egenskapen är nullassocieras den aktuella systemkulturen med tråden.

Programmering med programdomäner

Programdomäner skapas och manipuleras vanligtvis programmatiskt av runtime-värdar. Ibland kanske ett program också vill arbeta med programdomäner. Ett programprogram kan till exempel läsa in en programkomponent i en domän för att kunna ta bort domänen (och komponenten) utan att behöva stoppa hela programmet.

AppDomain är det programmatiska gränssnittet för programdomäner. Den här klassen innehåller metoder för att skapa och ta bort domäner, skapa instanser av typer i domäner och registrera dig för olika meddelanden, till exempel avlastning av programdomäner. I följande tabell visas vanliga AppDomain metoder.

AppDomain-metod beskrivning
CreateDomain Skapar en ny programdomän. Vi rekommenderar att du använder en överlagring av den här metoden som anger ett AppDomainSetup objekt. Det här är det bästa sättet att ange egenskaperna för en ny domän, till exempel programbasen eller rotkatalogen för programmet. platsen för konfigurationsfilen för domänen. och sökvägen som den vanliga språkkörningen ska använda för att läsa in sammansättningar i domänen.
ExecuteAssembly och ExecuteAssemblyByName Kör en sammansättning i programdomänen. Det här är en instansmetod, så den kan användas för att köra kod i en annan programdomän som du har en referens till.
CreateInstanceAndUnwrap Skapar en instans av en angiven typ i programdomänen och returnerar en proxy. Använd den här metoden för att undvika att läsa in sammansättningen som innehåller den skapade typen i den anropande sammansättningen.
Unload Utför en graciös avstängning av domänen. Programdomänen tas inte bort förrän alla trådar som körs i domänen antingen har stoppats eller inte längre finns i domänen.

Kommentar

Den vanliga språkkörningen stöder inte serialisering av globala metoder, så ombud kan inte användas för att köra globala metoder i andra programdomäner.

De ohanterade gränssnitt som beskrivs i common language runtime Hosting Interfaces Specification ger också åtkomst till programdomäner. Runtime-värdar kan använda gränssnitt från ohanterad kod för att skapa och få åtkomst till programdomänerna i en process.

Miljövariabeln COMPLUS_LoaderOptimization

En miljövariabel som anger standardprincipen för inläsningsoptimering för ett körbart program.

Syntax

COMPLUS_LoaderOptimization = 1

Kommentarer

Ett typiskt program läser in flera sammansättningar i en programdomän innan koden de innehåller kan köras.

Hur sammansättningen läses in avgör om dess jit-kompilerade kod (just-in-time) kan delas av flera programdomäner i processen.

  • Om en sammansättning läses in domänneutral kan alla programdomäner som delar samma säkerhetsbeviljande uppsättning dela samma JIT-kompilerade kod. Detta minskar det minne som krävs av programmet.

  • Om en sammansättning inte läses in domänneutral måste den vara JIT-kompilerad i alla programdomäner där den läses in och inläsaren får inte dela interna resurser mellan programdomäner.

När den är inställd på 1 tvingar COMPLUS_LoaderOptimization miljöflaggan körningsvärden att läsa in alla sammansättningar på ett icke-domänneutralt sätt som kallas SingleDomain. SingleDomain läser inte in några sammansättningar som domänneutrala, förutom Mscorlib, som alltid läses in domänneutralt. Den här inställningen kallas enkel domän eftersom den ofta används när värden bara kör ett enda program i processen.

Varning

Miljöflaggan COMPLUS_LoaderOptimization har utformats för att användas i diagnostik- och testscenarier. Om flaggan är aktiverad kan det orsaka allvarlig långsam och ökad minnesanvändning.

Kodexempel

Om du vill tvinga alla sammansättningar att inte läsas in som domänneutrala för IISADMIN-tjänsten kan du uppnå genom att lägga COMPLUS_LoaderOptimization=1 till miljöns multisträngsvärde i nyckeln 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

Se även