Share via


Beheerd uitvoeringsproces

Het beheerde uitvoeringsproces bevat de volgende stappen, die verderop in dit onderwerp uitgebreid worden besproken:

  1. Een compiler kiezen. Als u de voordelen van de algemene taalruntime wilt verkrijgen, moet u een of meer taalcompilers gebruiken die gericht zijn op de runtime.
  2. Uw code compileren naar tussenliggende taal. Compileren vertaalt uw broncode in algemene tussenliggende taal (CIL) en genereert de vereiste metagegevens.
  3. CIL compileren naar systeemeigen code. Tijdens de uitvoering vertaalt een Just-In-Time-compiler (JIT) het CIL in systeemeigen code. Tijdens deze compilatie moet code een verificatieproces doorgeven dat de CIL en metagegevens onderzoekt om erachter te komen of de code veilig kan worden bepaald.
  4. Code uitvoeren. De algemene taalruntime biedt de infrastructuur waarmee uitvoering kan plaatsvinden en services die kunnen worden gebruikt tijdens de uitvoering.

Een compiler kiezen

Als u de voordelen van de Common Language Runtime (CLR) wilt verkrijgen, moet u een of meer taalcompilatoren gebruiken die gericht zijn op de runtime, zoals Visual Basic, C#, Visual C++, F#, of een van de vele compilers van derden, zoals een Compiler van Een Eif, Perl of COBOL-compiler.

Omdat het een omgeving met meerdere talen is, ondersteunt de runtime een groot aantal gegevenstypen en taalfuncties. De taalcompiler die u gebruikt, bepaalt welke runtime-functies beschikbaar zijn en u ontwerpt uw code met deze functies. Uw compiler, niet de runtime, brengt de syntaxis vast die uw code moet gebruiken. Als uw onderdeel volledig bruikbaar moet zijn door onderdelen die zijn geschreven in andere talen, moeten de geëxporteerde typen van uw onderdeel alleen taalfuncties weergeven die zijn opgenomen in de Common Language Specification (CLS). U kunt het CLSCompliantAttribute kenmerk gebruiken om ervoor te zorgen dat uw code CLS-compatibel is. Zie Taalonafhankelijkheid en taalonafhankelijke onderdelen voor meer informatie.

Compileren naar CIL

Bij het compileren van beheerde code vertaalt de compiler uw broncode in algemene tussenliggende taal (CIL), een CPU-onafhankelijke set instructies die efficiënt kunnen worden geconverteerd naar systeemeigen code. CIL bevat instructies voor het laden, opslaan, initialiseren en aanroepen van methoden voor objecten, evenals instructies voor rekenkundige en logische bewerkingen, controlestroom, directe geheugentoegang, uitzonderingsafhandeling en andere bewerkingen. Voordat code kan worden uitgevoerd, moet CIL worden geconverteerd naar CPU-specifieke code, meestal door een JIT-compiler (Just-In-Time). Omdat de algemene taalruntime een of meer JIT-compilers levert voor elke computerarchitectuur die wordt ondersteund, kan dezelfde set CIL worden gecompileerd en uitgevoerd op elke ondersteunde architectuur.

Wanneer een compiler CIL produceert, worden ook metagegevens geproduceerd. Metagegevens beschrijven de typen in uw code, inclusief de definitie van elk type, de handtekeningen van de leden van elk type, de leden waarnaar uw code verwijst en andere gegevens die de runtime tijdens de uitvoering gebruikt. De CIL en metagegevens bevinden zich in een draagbaar uitvoerbaar bestand (PE) waarop de gepubliceerde Microsoft PE en common object-bestandsindeling (COFF) die historisch worden gebruikt voor uitvoerbare inhoud. Met deze bestandsindeling, die geschikt is voor CIL of systeemeigen code en metagegevens, kan het besturingssysteem algemene taalruntime-installatiekopieën herkennen. Door de aanwezigheid van metagegevens in het bestand samen met CIL kan uw code zichzelf beschrijven, wat betekent dat er geen typebibliotheken of IdL (Interface Definition Language) nodig zijn. De runtime zoekt en extraheert de metagegevens uit het bestand zo nodig tijdens de uitvoering.

CIL compileren naar systeemeigen code

Voordat u algemene tussenliggende taal (CIL) kunt uitvoeren, moet deze worden gecompileerd op basis van de algemene taalruntime naar systeemeigen code voor de doelcomputerarchitectuur. .NET biedt twee manieren om deze conversie uit te voeren:

Compilatie door de JIT-compiler

JIT-compilatie converteert CIL naar systeemeigen code op aanvraag tijdens runtime van de toepassing, wanneer de inhoud van een assembly wordt geladen en uitgevoerd. Omdat de algemene taalruntime een JIT-compiler levert voor elke ondersteunde CPU-architectuur, kunnen ontwikkelaars een set CIL-assembly's bouwen die kunnen worden gecompileerd en uitgevoerd op verschillende computers met verschillende computerarchitecturen. Als uw beheerde code echter platformspecifieke systeemeigen API's of een platformspecifieke klassebibliotheek aanroept, wordt deze alleen op dat besturingssysteem uitgevoerd.

JIT-compilatie houdt rekening met de mogelijkheid dat bepaalde code nooit wordt aangeroepen tijdens de uitvoering. In plaats van tijd en geheugen te gebruiken om alle CIL in een PE-bestand te converteren naar systeemeigen code, wordt het CIL zo nodig tijdens het uitvoeren geconverteerd en wordt de resulterende systeemeigen code in het geheugen opgeslagen, zodat deze toegankelijk is voor volgende aanroepen in de context van dat proces. Het laadprogramma maakt en koppelt een stub aan elke methode in een type wanneer het type wordt geladen en geïnitialiseerd. Wanneer een methode voor het eerst wordt aangeroepen, geeft de stub het besturingselement door aan de JIT-compiler, waarmee de CIL voor die methode wordt geconverteerd naar systeemeigen code en de stub wordt gewijzigd om rechtstreeks naar de gegenereerde systeemeigen code te verwijzen. Daarom gaan volgende aanroepen naar de gecompileerde JIT-methode rechtstreeks naar de systeemeigen code.

Generatie van installatietijdcode met behulp van NGen.exe

Omdat de JIT-compiler het CIL van een assembly converteert naar systeemeigen code wanneer afzonderlijke methoden die in die assembly zijn gedefinieerd, worden aangeroepen, is dit van invloed op de prestaties tijdens runtime. In de meeste gevallen is dat verminderde prestaties acceptabel. Belangrijker is dat de code die door de JIT-compiler wordt gegenereerd, afhankelijk is van het proces dat de compilatie heeft geactiveerd. Het kan niet worden gedeeld over meerdere processen. Om toe te staan dat de gegenereerde code wordt gedeeld via meerdere aanroepen van een toepassing of meerdere processen die een set assembly's delen, ondersteunt de algemene taalruntime een compilatiemodus van tevoren. In deze compilatiemodus van tevoren wordt de Ngen.exe (Native Image Generator) gebruikt om CIL-assembly's te converteren naar systeemeigen code, net zoals de JIT-compiler wel doet. De werking van Ngen.exe verschilt echter op drie manieren van die van de JIT-compiler:

  • De conversie wordt uitgevoerd van CIL naar systeemeigen code voordat de toepassing wordt uitgevoerd in plaats van terwijl de toepassing wordt uitgevoerd.
  • Hiermee wordt een hele assembly tegelijk gecompileerd, in plaats van één methode tegelijk.
  • De gegenereerde code in de systeemeigen installatiekopieëncache blijft behouden als een bestand op schijf.

Codeverificatie

Als onderdeel van de compilatie naar systeemeigen code moet de CIL-code een verificatieproces doorgeven, tenzij een beheerder een beveiligingsbeleid heeft ingesteld waarmee de code verificatie kan omzeilen. Verificatie onderzoekt CIL en metagegevens om erachter te komen of de code veilig is, wat betekent dat deze alleen toegang heeft tot de geheugenlocaties waartoe de code toegang heeft. Typeveiligheid helpt bij het isoleren van objecten van elkaar en helpt ze te beschermen tegen onbedoelde of schadelijke beschadiging. Het biedt ook zekerheid dat beveiligingsbeperkingen voor code betrouwbaar kunnen worden afgedwongen.

De runtime is afhankelijk van het feit dat de volgende instructies waar zijn voor code die verifieerbaar veilig is:

  • Een verwijzing naar een type is strikt compatibel met het type waarnaar wordt verwezen.
  • Alleen op de juiste wijze gedefinieerde bewerkingen worden aangeroepen op een object.
  • Identiteiten zijn wat ze beweren te zijn.

Tijdens het verificatieproces wordt CIL-code onderzocht in een poging om te bevestigen dat de code toegang heeft tot geheugenlocaties en methoden alleen kan aanroepen via correct gedefinieerde typen. Code kan bijvoorbeeld niet toestaan dat de velden van een object worden geopend op een manier waarmee geheugenlocaties kunnen worden overschreden. Daarnaast controleert de verificatie code om te bepalen of de CIL correct is gegenereerd, omdat een onjuiste CIL kan leiden tot een schending van de beveiligingsregels van het type. Het verificatieproces geeft een goed gedefinieerde set typeveilige code door en geeft alleen code door die veilig is. Sommige typeveilige code kan echter geen verificatie doorgeven vanwege enkele beperkingen van het verificatieproces, en sommige talen produceren standaard geen verifieerbare typeveilige code. Als typeveilige code is vereist voor het beveiligingsbeleid, maar de code geen verificatie doorgeeft, wordt er een uitzondering gegenereerd wanneer de code wordt uitgevoerd.

Code uitvoeren

De algemene taalruntime biedt de infrastructuur waarmee beheerde uitvoering kan plaatsvinden en services die kunnen worden gebruikt tijdens de uitvoering. Voordat een methode kan worden uitgevoerd, moet deze worden gecompileerd naar processorspecifieke code. Elke methode waarvoor CIL is gegenereerd, wordt JIT gecompileerd wanneer deze voor het eerst wordt aangeroepen en vervolgens wordt uitgevoerd. De volgende keer dat de methode wordt uitgevoerd, wordt de bestaande systeemeigen JIT-code uitgevoerd. Het proces van JIT-compilatie en het uitvoeren van de code wordt herhaald totdat de uitvoering is voltooid.

Tijdens de uitvoering ontvangt beheerde code services zoals garbagecollection, beveiliging, interoperabiliteit met niet-beheerde code, ondersteuning voor foutopsporing in meerdere talen en verbeterde ondersteuning voor implementatie en versiebeheer.

In Microsoft Windows Vista controleert het besturingssysteemlader op beheerde modules door een beetje in de COFF-header te onderzoeken. De bit die wordt ingesteld, geeft een beheerde module aan. Als het laadprogramma beheerde modules detecteert, wordt mscoree.dll geladen en _CorValidateImage_CorImageUnloading wordt het laadprogramma gewaarschuwd wanneer de installatiekopieën van de beheerde module worden geladen en verwijderd. _CorValidateImage voert de volgende acties uit:

  1. Zorgt ervoor dat de code geldige beheerde code is.
  2. Hiermee wijzigt u het toegangspunt in de afbeelding in een toegangspunt in de runtime.

In 64-bits Windows _CorValidateImage wijzigt u de afbeelding die zich in het geheugen bevindt door deze te transformeren van PE32 naar PE32+-indeling.

Zie ook