Freigeben über


Der verwaltete Ausführungsprozess

Der Prozess der verwalteten Ausführung umfasst die folgenden Schritte, die weiter unten in diesem Thema ausführlich erläutert werden:

  1. Auswählen eines Compilers. Um die Vorteile der Common Language Runtime zu erhalten, müssen Sie einen oder mehrere Sprachcompiler verwenden, die auf die Laufzeit abzielen.
  2. Kompilieren Sie Ihren Code in die Zwischensprache. Durch kompilieren wird der Quellcode in eine gemeinsame Zwischensprache (CIL) übersetzt und die erforderlichen Metadaten generiert.
  3. Kompilieren von CIL in nativen Code. Zur Laufzeit übersetzt ein JIT-Compiler (Just-in-Time) die CIL in systemeigenen Code. Während dieser Kompilierung muss der Code einen Überprüfungsprozess übergeben, der die CIL und Metadaten überprüft, um herauszufinden, ob der Code als typsicher festgelegt werden kann.
  4. Ausführen von Code. Die Common Language Runtime stellt die Infrastruktur bereit, die die Ausführung ermöglicht, und Dienste, die während der Ausführung verwendet werden können.

Auswählen eines Compilers

Um die Vorteile der Common Language Runtime (CLR) zu erhalten, müssen Sie einen oder mehrere Sprachcompiler verwenden, die auf die Laufzeit abzielen, z. B. Visual Basic, C#, Visual C++, F#, oder einen von vielen Drittanbietercompilern, z. B. einen Xaml-, Perl- oder COBOL-Compiler.

Da es sich um eine mehrsprachige Ausführungsumgebung handelt, unterstützt die Laufzeit eine Vielzahl von Datentypen und Sprachfeatures. Der verwendete Sprachcompiler bestimmt, welche Laufzeitfeatures verfügbar sind, und Sie entwerfen Ihren Code mithilfe dieser Features. Der Compiler, nicht die Laufzeit, richtet die Syntax ein, die ihr Code verwenden muss. Wenn Ihre Komponente vollständig von Komponenten verwendet werden muss, die in anderen Sprachen geschrieben wurden, müssen die exportierten Typen Ihrer Komponente nur Sprachfeatures verfügbar machen, die in der Common Language Specification (CLS) enthalten sind. Sie können das CLSCompliantAttribute Attribut verwenden, um sicherzustellen, dass Ihr Code CLS-kompatibel ist. Weitere Informationen finden Sie unter Sprachunabhängigkeit und sprachunabhängige Komponenten.

Kompilieren in CIL

Beim Kompilieren von verwaltetem Code übersetzt der Compiler Den Quellcode in eine gemeinsame Zwischensprache (CIL), bei der es sich um einen CPU-unabhängigen Satz von Anweisungen handelt, die effizient in systemeigenen Code konvertiert werden können. CIL enthält Anweisungen zum Laden, Speichern, Initialisieren und Aufrufen von Methoden für Objekte sowie Anweisungen für arithmetische und logische Vorgänge, Steuerungsfluss, direkten Speicherzugriff, Ausnahmebehandlung und andere Vorgänge. Bevor Code ausgeführt werden kann, muss CIL in CPU-spezifischen Code konvertiert werden, in der Regel durch einen Just-in-Time-Compiler (JIT). Da die Common Language Runtime einen oder mehrere JIT-Compiler für jede von ihr unterstützte Computerarchitektur bereitstellt, kann derselbe Satz von CIL JIT-kompiliert und auf jeder unterstützten Architektur ausgeführt werden.

Wenn ein Compiler CIL erzeugt, erzeugt er auch Metadaten. Metadaten beschreiben die Typen in Ihrem Code, einschließlich der Definition jedes Typs, der Signaturen der Mitglieder jedes Typs, der Mitglieder, auf die Ihr Code verweist, und andere Daten, die die Laufzeit während der Ausführung verwendet. Die CIL und die Metadaten sind in einer portablen ausführbaren Datei (PE) enthalten, die auf dem veröffentlichten Microsoft PE-Format basiert und das allgemeine Objektdateiformat (COFF) erweitert, welches historisch für ausführbare Inhalte verwendet wird. Dieses Dateiformat, das CIL oder nativen Code sowie Metadaten enthält, ermöglicht es dem Betriebssystem, Common Language Runtime-Images zu erkennen. Das Vorhandensein von Metadaten in der Datei zusammen mit CIL ermöglicht es Ihrem Code, sich selbst zu beschreiben, was bedeutet, dass es keine Notwendigkeit für Typbibliotheken oder Schnittstellendefinitionssprache (Interface Definition Language, IDL) gibt. Die Laufzeit sucht und extrahiert die Metadaten aus der Datei nach Bedarf während der Ausführung.

Kompiliere CIL zu nativem Code

Bevor CIL-Code (Common Language Runtime) ausgeführt werden kann, muss er in der Common Language Runtime in nativen Code für die Architektur des Zielcomputers kompiliert werden. .NET bietet zwei Möglichkeiten zum Ausführen dieser Konvertierung:

Kompilierung durch den JIT-Compiler

Bei der JIT-Kompilierung wird CIL-Code zur Anwendungslaufzeit auf Abruf in nativen Code konvertiert, sobald der Inhalt einer Assembly geladen und ausgeführt wird. Da die Common Language Runtime einen JIT-Compiler für jede unterstützte CPU-Architektur bereitstellt, können Entwickler eine Reihe von CIL-Assemblys erstellen, die JIT-kompiliert und auf verschiedenen Computern mit unterschiedlichen Computerarchitekturen ausgeführt werden können. Wenn Ihr verwalteter Code jedoch plattformspezifische systemeigene APIs oder eine plattformspezifische Klassenbibliothek aufruft, wird er nur auf diesem Betriebssystem ausgeführt.

DIE JIT-Kompilierung berücksichtigt die Möglichkeit, dass während der Ausführung möglicherweise kein Code aufgerufen wird. Anstatt Zeit und Arbeitsspeicher zu verwenden, um alle CIL in einer PE-Datei in systemeigenen Code zu konvertieren, konvertiert es die CIL nach Bedarf während der Ausführung und speichert den resultierenden systemeigenen Code im Arbeitsspeicher, sodass er für nachfolgende Aufrufe im Kontext dieses Prozesses zugänglich ist. Das Ladeprogramm erstellt einen Stub und fügt diesen an jede Methode des Typs an, wenn dieser Typ geladen und initialisiert wird. Wenn eine Methode zum ersten Mal aufgerufen wird, übergibt der Stub das Steuerelement an den JIT-Compiler, der die CIL für diese Methode in systemeigenen Code konvertiert und den Stub so ändert, dass er direkt auf den generierten systemeigenen Code verweist. Daher wechseln nachfolgende Aufrufe der JIT-kompilierten Methode direkt zum systemeigenen Code.

Codegenerierung bei der Installation mithilfe von NGen.exe

Da der JIT-Compiler die CIL einer Assembly in systemeigenen Code konvertiert, wenn einzelne in dieser Assembly definierte Methoden aufgerufen werden, wirkt sich dies negativ auf die Leistung zur Laufzeit aus. In den meisten Fällen ist diese verringerte Leistung akzeptabel. Wichtiger ist, dass der vom JIT-Compiler generierte Code an den Prozess gebunden ist, der die Kompilierung ausgelöst hat. Sie kann nicht über mehrere Prozesse hinweg freigegeben werden. Damit der generierte Code über mehrere Aufrufe einer Anwendung oder über mehrere Prozesse hinweg freigegeben werden kann, die eine Gruppe von Assemblys gemeinsam nutzen, unterstützt die Common Language Runtime einen Vorabkompilierungsmodus. Dieser Vorabkompilierungsmodus verwendet den Ngen.exe (Native Image Generator) zum Konvertieren von CIL-Assemblys in systemeigenen Code ähnlich wie der JIT-Compiler. Der Betrieb von Ngen.exe unterscheidet sich jedoch von dem des JIT-Compilers auf drei Arten:

  • Sie führt die Konvertierung von CIL in nativen Code durch, bevor die Anwendung läuft, anstatt während die Anwendung läuft.
  • Es kompiliert jeweils eine gesamte Assembly anstelle einer Methode gleichzeitig.
  • Er speichert den generierten Code im nativen Imagecache als Datei auf dem Datenträger.

Codeüberprüfung

Im Rahmen der Kompilierung in systemeigenem Code muss der CIL-Code einen Überprüfungsprozess bestehen, es sei denn, ein Administrator hat eine Sicherheitsrichtlinie eingerichtet, mit der der Code die Überprüfung umgehen kann. Die Überprüfung untersucht CIL und Metadaten, um herauszufinden, ob der Code typsicher ist, was bedeutet, dass er nur auf die Speicherspeicherorte zugreift, auf die er für den Zugriff autorisiert ist. Die Typsicherheit hilft dabei, Objekte voneinander zu isolieren und sie vor versehentlicher oder böswilliger Beschädigung zu schützen. Es bietet außerdem sicherheit, dass Sicherheitseinschränkungen für Code zuverlässig erzwungen werden können.

Die Laufzeit basiert auf der Tatsache, dass die folgenden Anweisungen für Code gelten, der nachweislich typsicher ist:

  • Ein Verweis auf einen Typ ist streng mit dem Typ kompatibel, auf den verwiesen wird.
  • Nur ordnungsgemäß definierte Vorgänge werden für ein Objekt aufgerufen.
  • Identitäten sind das, was sie behaupten, sie zu sein.

Während des Überprüfungsprozesses wird der CIL-Code untersucht, um zu bestätigen, dass der Code nur über ordnungsgemäß definierte Typen auf Speicherspeicherorte zugreifen und Methoden aufrufen kann. Code kann z. B. nicht zulassen, dass auf die Felder eines Objekts auf eine Weise zugegriffen werden kann, mit der Speicherorte überschrieben werden können. Darüber hinaus prüft die Überprüfung den Code, um festzustellen, ob die CIL ordnungsgemäß generiert wurde, da falsche CIL zu einem Verstoß gegen die Typensicherheitsregeln führen kann. Der Überprüfungsprozess übergibt einen klar definierten Satz typsicheren Codes und übergibt nur Code, der typsicher ist. Ein typsicherer Code kann die Überprüfung jedoch aufgrund einiger Einschränkungen des Überprüfungsprozesses möglicherweise nicht bestehen, und einige Sprachen erzeugen standardmäßig keinen nachweisbaren typsicheren Code. Wenn typsicherer Code von der Sicherheitsrichtlinie verlangt wird, der Code jedoch die Überprüfung nicht besteht, wird eine Ausnahme ausgelöst, wenn der Code ausgeführt wird.

Ausführen von Code

Die Common Language Runtime stellt die Infrastruktur bereit, die es ermöglicht, die verwaltete Ausführung durchzuführen, und Dienste, die während der Ausführung verwendet werden können. Bevor eine Methode ausgeführt werden kann, muss sie in prozessorspezifischem Code kompiliert werden. Jede Methode, für die CIL generiert wurde, wird JIT-kompiliert, wenn sie zum ersten Mal aufgerufen und dann ausgeführt wird. Wenn die Methode das nächste Mal ausgeführt wird, wird der vorhandene JIT-kompilierte systemeigene Code ausgeführt. Der Prozess der JIT-Kompilierung und anschließendes Ausführen des Codes wird wiederholt, bis die Ausführung abgeschlossen ist.

Während der Ausführung empfängt verwalteter Code Dienste wie Garbage Collection, Sicherheit, Interoperabilität mit nicht verwaltetem Code, unterstützung für das sprachübergreifende Debuggen und erweiterte Bereitstellungs- und Versionsverwaltungsunterstützung.

In Microsoft Windows Vista sucht das Betriebssystemladeprogramm nach verwalteten Modulen, indem ein Bit im COFF-Header untersucht wird. Das festgelegte Bit gibt ein verwaltetes Modul an. Wenn das Ladeprogramm verwaltete Module erkennt, lädt es mscoree.dll, und _CorValidateImage und _CorImageUnloading benachrichtigen das Ladeprogramm, wenn die verwalteten Modulimages geladen und entladen werden. _CorValidateImage führt die folgenden Aktionen aus:

  1. Stellt sicher, dass der Code gültiger verwalteter Code ist.
  2. Ändert den Einstiegspunkt im Bild in einen Einstiegspunkt in der Laufzeit.

Unter 64-Bit-Windows modifiziert _CorValidateImage das im Arbeitsspeicher befindliche Bild, indem es von PE32 in das PE32+-Format transformiert wird.

Siehe auch