Ja, beim JIT'ing IL-Code wird die IL in native Maschinenanweisungen übersetzt.
Ja, die .NET-Laufzeit interagiert mit dem nativen JIT-Maschinencode in dem Sinne, dass die Laufzeit die Speicherblöcke besitzt, die vom nativen Maschinencode belegt sind, die Laufzeitaufrufe in den nativen Maschinencode usw.
Sie haben Recht, dass die .NET-Laufzeit den IL-Code in Ihren Assemblys nicht interpretiert.
Wenn die Ausführung eine Funktion oder einen Codeblock erreicht (z. B. eine else-Klausel eines if-Blocks), die noch nicht in nativen Maschinencode kompiliert wurde, wird die JIT'r aufgerufen, um diesen IL-Block in nativen Maschinencode zu kompilieren . Wenn dies erledigt ist, gibt die Programmausführung den frisch ausgegebenen Maschinencode ein, um die Programmlogik auszuführen. Wenn während der Ausführung dieses nativen Maschinencodes die Ausführung eines Funktionsaufrufs für eine Funktion erreicht wird, die noch nicht zu Maschinencode kompiliert wurde, wird die JIT'r aufgerufen, um diese Funktion "just in time" zu kompilieren . Und so weiter.
Das JIT'r kompiliert nicht unbedingt die gesamte Logik eines Funktionskörpers auf einmal in Maschinencode. Wenn die Funktion if-Anweisungen hat, werden die Anweisungsblöcke der if- oder else-Klauseln möglicherweise erst dann JIT-kompiliert, wenn die Ausführung diesen Block tatsächlich durchläuft. Codepfade, die nicht ausgeführt wurden, bleiben in IL-Form, bis sie ausgeführt werden.
Der kompilierte native Maschinencode wird im Speicher gespeichert, damit er bei der nächsten Ausführung dieses Codeabschnitts erneut verwendet werden kann. Wenn Sie eine Funktion zum zweiten Mal aufrufen, wird sie schneller ausgeführt als beim ersten Aufruf, da beim zweiten Mal kein JIT-Schritt erforderlich ist.
In Desktop .NET wird der native Maschinencode für die Lebensdauer der Appdomain gespeichert. In .NET CF wird der native Maschinencode möglicherweise weggeworfen, wenn der Anwendung der Arbeitsspeicher ausgeht. Bei der nächsten Ausführung dieses Codes wird die JIT erneut aus dem ursprünglichen IL-Code kompiliert.
Code wird in die Microsoft Intermediate Language "kompiliert", die dem Assemblyformat ähnelt.
Wenn Sie auf eine ausführbare Datei doppelklicken, wird Windows geladen,
mscoree.dll
das dann die CLR-Umgebung einrichtet und den Code Ihres Programms startet. Der JIT-Compiler beginnt mit dem Lesen des MSIL-Codes in Ihrem Programm und kompiliert den Code dynamisch in x86-Anweisungen, die die CPU ausführen kann.quelle
.NET verwendet eine Zwischensprache namens MSIL, die manchmal als IL abgekürzt wird. Der Compiler liest Ihren Quellcode und erzeugt MSIL. Wenn Sie das Programm ausführen, liest der JIT-Compiler (.NET Just In Time) Ihren MSIL-Code und erstellt eine ausführbare Anwendung im Speicher. Sie werden nichts davon sehen, aber es ist eine gute Idee zu wissen, was hinter den Kulissen vor sich geht.
quelle
Ich werde das Kompilieren von IL-Code in native CPU-Anweisungen anhand des folgenden Beispiels beschreiben.
In erster Linie kennt CLR alle Details über den Typ und welche Methode von diesem Typ aufgerufen wird, was auf Metadaten zurückzuführen ist.
Wenn die CLR beginnt, IL in der nativen CPU-Anweisung auszuführen, weist die CLR zu diesem Zeitpunkt interne Datenstrukturen für jeden Typ zu, auf den der Main-Code verweist.
In unserem Fall haben wir nur einen Typ Konsole, daher ordnet CLR über diese interne Struktur eine interne Datenstruktur zu, und wir verwalten den Zugriff auf die referenzierten Typen
Innerhalb dieser Datenstruktur enthält CLR Einträge zu allen von diesem Typ definierten Methoden. Jeder Eintrag enthält die Adresse, an der sich die Implementierung der Methode befindet.
Bei der Initialisierung dieser Struktur setzt CLR jeden Eintrag in undokumentierte FUNCTION, die in CLR selbst enthalten ist. Und wie Sie sich vorstellen können, wird diese FUNCTION als JIT-Compiler bezeichnet.
Insgesamt können Sie JIT Compiler als CLR-Funktion betrachten, die IL in native CPU-Anweisungen kompiliert. Lassen Sie mich Ihnen im Detail zeigen, wie dieser Prozess in unserem Beispiel ablaufen wird.
1.Wenn Main's WriteLine zum ersten Mal aufruft, wird die JITCompiler-Funktion aufgerufen.
2. Die JIT-Compilerfunktion weiß, welche Methode aufgerufen wird und welcher Typ diese Methode definiert.
3.Dann durchsucht der Jit Compiler die Assembly, in der dieser Typ definiert wurde, und ruft den IL-Code für die von diesem Typ definierte Methode ab, in unserem Fall den IL-Code der WriteLine-Methode.
4.JIT-Compiler ordnen DYNAMIC- Speicherblock zu, danach überprüft und kompiliert JIT IL-Code in nativen CPU-Code und speichert diesen CPU-Code in diesem Speicherblock.
5.Dann kehrt der JIT-Compiler zum internen Datenstruktureintrag zurück und ersetzt die Adresse (die sich hauptsächlich auf die IL-Code-Implementierung von WriteLine bezieht) durch einen neuen dynamisch erstellten Speicherblock, der native CPU-Anweisungen von WriteLine enthält.
6. Schließlich springt die JIT-Compiler-Funktion zum Code im Speicherblock. Dieser Code ist die Implementierung der WriteLine-Methode.
7.Nach der Implementierung der WriteLine kehrt der Code zum Hauptcode zurück, der die Ausführung wie gewohnt fortsetzt.
quelle
.NET Framework verwendet die CLR-Umgebung, um die MSIL (Microsoft Intermediate Language) zu erstellen, die auch als IL bezeichnet wird. Der Compiler liest Ihren Quellcode und generiert beim Erstellen / Kompilieren Ihres Projekts MSIL. Wenn Sie nun Ihr Projekt endgültig ausführen, wird der .NET JIT ( Just-in-Time-Compiler ) aktiviert. JIT liest Ihren MSIL-Code und erzeugt nativen Code (x86-Anweisungen), der von der CPU einfach ausgeführt werden kann. JIT liest alle MSIL-Anweisungen und führt sie Zeile für Zeile aus.
Wenn Sie interessiert sind, was hinter den Kulissen passiert, wurde dies bereits beantwortet. Bitte folgen Sie - hier
quelle