Hanterad körningsprocess
Den hanterade körningsprocessen innehåller följande steg, som beskrivs i detalj senare i det här avsnittet:
- Välja en kompilator. För att få de fördelar som tillhandahålls av den gemensamma språkkörningen måste du använda en eller flera språkkompilatorer som är inriktade på körningen.
- Kompilera koden till mellanliggande språk. Kompileringen översätter källkoden till det gemensamma mellanliggande språket (CIL) och genererar nödvändiga metadata.
- Kompilera CIL till intern kod. Vid körning översätter en JIT-kompilator (just-in-time) CIL till inbyggd kod. Under den här kompileringen måste koden skicka en verifieringsprocess som undersöker CIL och metadata för att ta reda på om koden kan fastställas vara typsäker.
- Kör kod. Den vanliga språkkörningen tillhandahåller infrastrukturen som gör det möjligt att köra och tjänster som kan användas under körningen.
Välj en kompilator
För att få fördelarna med common language runtime (CLR) måste du använda en eller flera språkkompilatorer som riktar sig mot körningen, till exempel Visual Basic, C#, Visual C++, F# eller någon av många kompilatorer från tredje part, till exempel en Eiffel-, Perl- eller COBOL-kompilator.
Eftersom det är en körningsmiljö med flera språk stöder körningsmiljön en mängd olika datatyper och språkfunktioner. Språkkompilatorn som du använder avgör vilka körningsfunktioner som är tillgängliga och du utformar koden med hjälp av dessa funktioner. Kompilatorn, inte körningen, etablerar den syntax som koden måste använda. Om komponenten måste vara helt användbar av komponenter som skrivits på andra språk, får komponentens exporterade typer endast exponera språkfunktioner som ingår i CLS (Common Language Specification). Du kan använda attributet CLSCompliantAttribute för att säkerställa att koden är CLS-kompatibel. Mer information finns i Språkoberoende och språkoberoende komponenter.
Kompilera till CIL
Vid kompilering till hanterad kod översätter kompilatorn källkoden till ett gemensamt mellanliggande språk (CIL), vilket är en CPU-oberoende uppsättning instruktioner som effektivt kan konverteras till inbyggd kod. CIL innehåller instruktioner för inläsning, lagring, initiering och anrop av objekt, samt instruktioner för aritmetiska och logiska åtgärder, kontrollflöde, direkt minnesåtkomst, undantagshantering och andra åtgärder. Innan koden kan köras måste CIL konverteras till CPU-specifik kod, vanligtvis av en JIT-kompilator (just-in-time). Eftersom den vanliga språkkörningen tillhandahåller en eller flera JIT-kompilatorer för varje datorarkitektur som stöds, kan samma uppsättning CIL vara JIT-kompilerad och köras på alla arkitekturer som stöds.
När en kompilator skapar CIL genererar den även metadata. Metadata beskriver typerna i koden, inklusive definitionen av varje typ, signaturerna för varje typs medlemmar, de medlemmar som koden refererar till och andra data som körningen använder vid körning. CIL och metadata finns i en portabel körbar fil (PE) som är baserad på och som utökar det publicerade Microsoft PE och det gemensamma objektfilformatet (COFF) som används historiskt för körbart innehåll. Det här filformatet, som rymmer CIL eller intern kod samt metadata, gör det möjligt för operativsystemet att känna igen vanliga språkkörningsavbildningar. Förekomsten av metadata i filen tillsammans med CIL gör att koden kan beskriva sig själv, vilket innebär att det inte finns något behov av typbibliotek eller gränssnittsdefinitionsspråk (IDL). Körningen letar upp och extraherar metadata från filen efter behov under körningen.
Kompilera CIL till intern kod
Innan du kan köra CIL (Common Intermediate Language) måste det kompileras mot den gemensamma språkkörningen till intern kod för måldatorarkitekturen. .NET tillhandahåller två sätt att utföra den här konverteringen:
- En JIT-kompilator (just-in-time).
- Ngen.exe (inbyggd avbildningsgenerator).
Kompilering av JIT-kompilatorn
JIT-kompilering konverterar CIL till intern kod på begäran vid programkörning, när innehållet i en sammansättning läses in och körs. Eftersom den vanliga språkkörningen tillhandahåller en JIT-kompilator för varje processorarkitektur som stöds kan utvecklare skapa en uppsättning CIL-sammansättningar som kan JIT-kompileras och köras på olika datorer med olika datorarkitekturer. Men om din hanterade kod anropar plattformsspecifika interna API:er eller ett plattformsspecifikt klassbibliotek körs den endast på det operativsystemet.
JIT-kompilering tar hänsyn till möjligheten att viss kod aldrig anropas under körningen. I stället för att använda tid och minne för att konvertera all CIL i en PE-fil till intern kod konverterar den CIL efter behov under körningen och lagrar den resulterande interna koden i minnet så att den är tillgänglig för efterföljande anrop i samband med den processen. Inläsaren skapar och kopplar en stub till varje metod i en typ när typen läses in och initieras. När en metod anropas för första gången skickar stub-filen kontroll till JIT-kompilatorn, som konverterar CIL för den metoden till intern kod och ändrar stub så att den pekar direkt på den genererade interna koden. Därför går efterföljande anrop till den JIT-kompilerade metoden direkt till den interna koden.
Kodgenerering för installationstid med hjälp av NGen.exe
Eftersom JIT-kompilatorn konverterar en sammansättnings CIL till intern kod när enskilda metoder som definierats i sammansättningen anropas, påverkar det prestandan negativt vid körning. I de flesta fall är den minskade prestandan acceptabel. Ännu viktigare är att koden som genereras av JIT-kompilatorn är bunden till den process som utlöste kompileringen. Det kan inte delas mellan flera processer. För att den genererade koden ska kunna delas över flera anrop av ett program eller över flera processer som delar en uppsättning sammansättningar, stöder den gemensamma språkkörningen ett kompileringsläge i förväg. Det här kompileringsläget i förväg använder Ngen.exe (inbyggd avbildningsgenerator) för att konvertera CIL-sammansättningar till intern kod ungefär som JIT-kompilatorn gör. Hur Ngen.exe fungerar skiljer sig dock från JIT-kompilatorns på tre sätt:
- Den utför konverteringen från CIL till intern kod innan programmet körs i stället för medan programmet körs.
- Den kompilerar en hel sammansättning i taget i stället för en metod i taget.
- Den bevarar den genererade koden i den interna avbildningscacheminnet som en fil på disken.
Kodverifiering
Som en del av kompileringen till den interna koden måste CIL-koden skicka en verifieringsprocess såvida inte en administratör har upprättat en säkerhetsprincip som tillåter att koden kringgår verifieringen. Verifiering undersöker CIL och metadata för att ta reda på om koden är typsäker, vilket innebär att den endast kommer åt de minnesplatser som den har behörighet att komma åt. Typsäkerhet hjälper till att isolera objekt från varandra och skyddar dem från oavsiktlig eller skadlig skada. Det ger också garantier för att säkerhetsbegränsningar för kod kan tillämpas på ett tillförlitligt sätt.
Körningen förlitar sig på det faktum att följande instruktioner är sanna för kod som är verifierbart typsäker:
- En referens till en typ är strikt kompatibel med den typ som refereras.
- Endast korrekt definierade åtgärder anropas på ett objekt.
- Identiteter är vad de påstår sig vara.
Under verifieringsprocessen undersöks CIL-kod i ett försök att bekräfta att koden endast kan komma åt minnesplatser och anropsmetoder via korrekt definierade typer. Kod kan till exempel inte tillåta att ett objekts fält nås på ett sätt som gör att minnesplatser kan överskridas. Dessutom kontrollerar verifieringen koden för att avgöra om CIL har genererats korrekt, eftersom felaktig CIL kan leda till en överträdelse av typsäkerhetsreglerna. Verifieringsprocessen skickar en väldefinierad uppsättning typsäker kod och skickar endast kod som är typsäker. En del typsäker kod kanske dock inte klarar verifieringen på grund av vissa begränsningar i verifieringsprocessen, och vissa språk producerar inte verifierbart typsäker kod. Om typsäker kod krävs av säkerhetsprincipen men koden inte godkänns, utlöses ett undantag när koden körs.
Köra koden
Den vanliga språkkörningen tillhandahåller den infrastruktur som gör att hanterad körning kan äga rum och tjänster som kan användas under körningen. Innan en metod kan köras måste den kompileras till processorspecifik kod. Varje metod som CIL har genererats för är JIT-kompilerad när den anropas för första gången och körs sedan. Nästa gång metoden körs körs den befintliga JIT-kompilerade interna koden. Processen för JIT-kompilering och körning av koden upprepas tills körningen är klar.
Under körningen tar hanterad kod emot tjänster som skräpinsamling, säkerhet, samverkan med ohanterad kod, stöd för felsökning på flera språk samt förbättrat stöd för distribution och versionshantering.
I Microsoft Windows Vista söker operativsystemets inläsare efter hanterade moduler genom att undersöka en bit i COFF-huvudet. Den bit som anges anger en hanterad modul. Om inläsaren identifierar hanterade moduler läser den in mscoree.dll och _CorValidateImage
_CorImageUnloading
meddelar inläsaren när de hanterade modulbilderna läses in och tas bort. _CorValidateImage
utför följande åtgärder:
- Ser till att koden är giltig hanterad kod.
- Ändrar startpunkten i avbildningen till en startpunkt i körningen.
I 64-bitars Windows _CorValidateImage
ändrar den bild som finns i minnet genom att omvandla den från PE32 till PE32+-format.