Just-in-Time-Zusammenstellung

Im Computer, gerade rechtzeitig (Jit) Zusammenstellung (Auch Dynamische Übersetzung oder Laufzeitzusammenstellungen)[1] ist eine Art der Ausführung Computercode das beinhaltet Zusammenstellung während der Ausführung eines Programms (bei Laufzeit) und nicht vor der Ausführung.[2] Dies kann bestehen aus Quellcode Übersetzung, aber häufiger Bytecode Übersetzung zu Maschinensprache, was dann direkt ausgeführt wird. Ein System, der einen JIT -Compiler implementiert, analysiert in der Regel kontinuierlich den ausgestellten Code und identifiziert Teile des Code, bei dem die durch Kompilierung oder Neukompilierung gewonnene Beschleunigung den Overhead of Compiling dieses Codes überwiegen würde.

Die JIT -Zusammenstellung ist eine Kombination aus den beiden traditionellen Übersetzungsansätzen in den Maschinencode -Vorzeit Zusammenstellung (Aot) und Deutung- und kombiniert einige Vorteile und Nachteile von beiden.[2] Ungefähr die JIT -Kompilierung kombiniert die Geschwindigkeit des kompilierten Code mit der Flexibilität der Interpretation mit dem Overhead eines Dolmetschers und dem zusätzlichen Aufwand des Kompilierens und Verknüpfung (nicht nur interpretieren). JIT -Zusammenstellung ist eine Form von Dynamische Zusammenstellungund erlaubt Adaptive Optimierung wie zum Beispiel Dynamische Neukompilation und Mikroarchitektur-Spezifische Beschleunigung.[NB 1][3] Interpretation und JIT -Zusammenstellung sind besonders geeignet für Dynamische Programmiersprachen, wie das Laufzeitsystem verarbeiten kann spät gebunden Datentypen und setzen Sie Sicherheitsgarantien durch.

Geschichte

Der früheste veröffentlichte JIT -Compiler wird im Allgemeinen auf Arbeiten zugeschrieben LISPELN durch John McCarthy 1960.[4] In seinem wegweisenden Papier Rekursive Funktionen symbolischer Ausdrücke und ihre Berechnung nach Maschine, Teil I.Er erwähnt Funktionen, die während der Laufzeit übersetzt werden, und spart dadurch die Notwendigkeit, die Compiler -Ausgabe aufzusparen Lochkarten[5] (Obwohl dies genauer als "bekannt wäre" wäre "System kompilieren und gehen"). Ein weiteres frühes Beispiel war von Ken Thompson, der 1968 eine der ersten Anwendungen von gab Reguläre Ausdrücke, hier für Musteranpassung im Texteditor Qed.[6] Für die Geschwindigkeit implementierte Thompson eine regelmäßige Ausdrucksübereinstimmung durch Jiting to IBM 7094 Code auf dem Kompatibler Zeitaustauschsystem.[4] Eine einflussreiche Technik zum Ableiten des kompilierten Code aus der Interpretation wurde von Pionierarbeit von Pionierarbeit James G. Mitchell 1970, das er für die experimentelle Sprache implementierte LC².[7][8]

Smalltalk (c. 1983) Pionierrierte neue Aspekte von JIT -Zusammenstellungen. Zum Beispiel wurde die Übersetzung des Maschinencodes auf Demand durchgeführt, und das Ergebnis wurde für die spätere Verwendung zwischengespeichert. Als das Gedächtnis knapp wurde, löschte das System einen Teil dieses Codes und regenerierte ihn, wenn es erneut benötigt wurde.[2][9] Sonne Selbst Die Sprache hat diese Techniken ausgiebig verbessert und war an einem Punkt das schnellste SmallTalk -System der Welt, was bis zu der Hälfte der Geschwindigkeit der optimierten C erreicht hat[10] aber mit einer vollständig objektorientierten Sprache.

Selbst wurde von der Sonne verlassen, aber die Forschung ging in die Java -Sprache. Der Begriff "Just-in-Time Compilation" wurde aus dem Fertigungszeitraum entlehnt "Gerade rechtzeitig"und populär von Java, wobei James Gosling den Begriff von 1993 nutzt.[11] Derzeit wird Jiting von den meisten Implementierungen der verwendet Java virtuelle Maschine, wie Hotspot baut auf diese Forschungsbasis auf und nutzt sie ausführlich.

Der HP -Projektdynamo war ein experimenteller JIT -Compiler, bei dem das Format "Bytecode" und das Maschinencode -Format gleich waren; Das System wurde PA-6000-Maschinencode in den Maschinencode verwandelt PA-8000 Maschinensprache.[12] Gegenintuitiv führte dies zu Geschwindigkeits-Ups, in einigen Fällen von 30%, da dies zu ermöglichten Optimierungen auf Maschinencodeebene, beispielsweise die Inlining-Code für eine bessere Nutzung von Cache und Optimierungen von Aufrufen von dynamischen Bibliotheken und vielen anderen Laufzeitoptimierungen, die konventionell sind Compiler können nicht versuchen.[13][14]

Im November 2020, Php 8.0 stellte einen JIT -Compiler ein.[15]

Entwurf

In einem Bytecode-kompilierten System, Quellcode wird in eine mittlere Darstellung übersetzt, die als bekannt ist Bytecode. Bytecode ist nicht der Maschinencode für einen bestimmten Computer und kann sein tragbar unter Computerarchitekturen. Der Bytecode kann dann durch interpretiert oder auf einem ausgeführt werden virtuelle Maschine. Der JIT -Compiler liest die Bytecodes in vielen Abschnitten (oder selten) und kompiliert sie dynamisch in den Maschinencode, damit das Programm schneller ausgeführt werden kann. Dies kann pro Datei, pro Funktion oder sogar auf einem beliebigen Codefragment erfolgen. Der Code kann kompiliert werden, wenn er ausgeführt werden soll (daher der Name "Just-in-Time") und später zwischengespeichert und wiederverwendet werden, ohne neu kompilieren zu müssen.

Dagegen ein traditionelles interpretierte virtuelle Maschine interpretiert einfach den Bytecode, im Allgemeinen mit einer viel geringeren Leistung. Etwas Dolmetschers interpretieren sogar den Quellcode, ohne den Schritt der ersten Kompilierung zu Bytecode, mit noch schlechterer Leistung. Statisch zusammengebildeter Code oder nativen Code wird vor dem Einsatz zusammengestellt. EIN Dynamische Kompilierungsumgebung ist eine, in der der Compiler während der Ausführung verwendet werden kann. Ein häufiges Ziel der Verwendung von JIT -Techniken ist es, die Leistung von zu erreichen oder zu übertreffen statische ZusammenstellungWährend die Vorteile der Bytecode -Interpretation beibehalten werden: Ein Groß . Der bereitgestellte Bytecode ist im Gegensatz zu dem nativen Code tragbar. Da die Laufzeit die Kontrolle über die Kompilierung hat, wie beispielsweise interpretierte Bytecode, kann sie in einer sicheren Sandbox ausgeführt werden. Compiler von Bytecode zum Maschinencode sind einfacher zu schreiben, da der tragbare Bytecode -Compiler bereits einen Großteil der Arbeit geleistet hat.

JIT -Code bietet im Allgemeinen eine weitaus bessere Leistung als Dolmetscher. Darüber hinaus kann es in einigen Fällen eine bessere Leistung als statische Zusammenstellung bieten, da viele Optimierungen nur zur Laufzeit möglich sind:[16][17]

  1. Die Zusammenstellung kann auf die gezielte CPU und das Betriebssystemmodell optimiert werden, in dem die Anwendung ausgeführt wird. Zum Beispiel kann JIT wählen SSE2 Vektor -CPU -Anweisungen, wenn feststellt, dass die CPU sie unterstützt. Um diese Optimierungsspezifität mit einem statischen Compiler zu erhalten, muss man entweder eine Binärdatei für jede beabsichtigte Plattform/Architektur kompilieren oder mehrere Versionen von Teilen des Codes innerhalb eines einzelnen Binärzusammenhiebs enthalten.
  2. Das System ist in der Lage, Statistiken darüber zu sammeln, wie das Programm tatsächlich in der Umgebung ausgeführt wird, in der es sich befindet, und kann für eine optimale Leistung neu ordnen und neu kompilieren. Einige statische Compiler können jedoch auch Profilinformationen als Eingabe aufnehmen.
  3. Das System kann globale Code -Optimierungen durchführen (z. Einbindung der Bibliotheksfunktionen) ohne die Vorteile der dynamischen Verknüpfung und ohne die Overheads, die statische Compiler und Linker innewohnt. Insbesondere bei globalen Inline-Substitutionen erfordert möglicherweise ein statischer Kompilierungsprozess für Laufzeitüberprüfungen und stellen sicher, dass ein virtueller Aufruf auftreten würde, wenn die tatsächliche Klasse des Objekts die eingeführte Methode überschreibt, und die Randbedingungsprüfungen für Array-Zugriffe müssen möglicherweise verarbeitet werden Innerhalb von Schleifen. In vielen Fällen kann diese Verarbeitung ausschleifen, die häufig einen hohen Geschwindigkeitserhöhung verleihen.
  4. Obwohl dies mit statisch kompilierten Müll gesammelten Sprachen möglich ist, kann ein Bytecode -System ausgeführte Code leichter für eine bessere Cache -Nutzung neu ordnen.

Da ein JIT zur Laufzeit ein nationales binäres Bild rendern und ausführen muss Harvard Architektur-basierte Maschine unmöglich; Gleiches gilt für bestimmte Betriebssysteme und virtuelle Maschinen. Eine besondere Art von "JIT" kann jedoch möglicherweise möglicherweise möglicherweise nicht Zielen Sie auf die CPU -Architektur der physischen Maschine, sondern auf einen optimierten VM -Bytecode, bei dem die Einschränkungen des Rohmaschinencodes vorherrschen, insbesondere dort, wo die VM dieses Bytecode letztendlich einen JIT für nativen Code nutzt.[18]

Leistung

JIT verursacht eine leichte bis bemerkenswerte Verzögerung bei der anfänglichen Ausführung einer Anwendung, da die Bytecode geladen und zusammengestellt wurde. Manchmal wird diese Verzögerung als "Startzeitverzögerung" oder "Aufwärmzeit" bezeichnet. Je mehr Optimierung JIT funktioniert, desto besser wird der Code, den er generiert, aber die anfängliche Verzögerung steigt ebenfalls. Ein JIT-Compiler muss daher einen Kompromiss zwischen der Kompilierungszeit und der Qualität des Codes einleiten, die er generieren möchte. Die Startzeit kann zusätzlich zur JIT-Zusammenstellung erhöhte IO-gebundene Operationen umfassen: Zum Beispiel die rt.jar Klassendatendatei für die Java virtuelle Maschine (JVM) ist 40 MB und das JVM muss in dieser kontextuell großen Datei viele Daten einholen.[19]

Eine mögliche Optimierung, die von Suns verwendet wird Hotspot Java Virtual Machine ist die Kombination von Interpretation und JIT -Zusammenstellung. Der Anwendungscode wird ursprünglich interpretiert, die JVM -Monitore, die Sequenzen von Sequenzen Bytecode werden häufig ausgeführt und übersetzt sie in den Maschinencode für die direkte Ausführung auf der Hardware. Für Bytecode, das nur wenige Male ausgeführt wird, spart dies die Kompilierungszeit und verringert die anfängliche Latenz. Für häufig ausgeführte Bytecode wird die JIT -Zusammenstellung nach einer Anfangsphase langsamer Interpretation mit hoher Geschwindigkeit ausgeführt. Da ein Programm die meiste Zeit damit verbringt, eine Minderheit seines Codes auszuführen, ist die verkürzte Kompilierungszeit erheblich. Schließlich können während der anfänglichen Code -Interpretation die Ausführungsstatistiken vor der Kompilierung erfasst werden, was dazu beiträgt, eine bessere Optimierung durchzuführen.[20]

Der richtige Kompromiss kann aufgrund von Umständen variieren. Zum Beispiel hat Suns Java Virtual Machine zwei Hauptmodi - Client und Server. Im Client -Modus wird eine minimale Zusammenstellung und Optimierung durchgeführt, um die Startzeit zu verkürzen. Im Servermodus wird eine umfangreiche Zusammenstellung und Optimierung durchgeführt, um die Leistung zu maximieren, sobald die Anwendung ausgeführt wird, indem die Startzeit geopfert wird. Andere Java-Just-in-Time-Compiler haben eine Laufzeitmessung der Häufigkeit verwendet, mit der eine Methode in Kombination mit der Bytecodegröße einer Methode als Heuristik ausgeführt wurde, um zu entscheiden, wann er kompiliert werden soll.[21] Ein weiteres verwendet die Häufigkeit, die mit der Erkennung von Schleifen kombiniert wurden.[22] Im Allgemeinen ist es viel schwieriger, genau vorherzusagen, welche Methoden in kurzfristigen Anwendungen optimieren können als in langjährigen.[23]

Native Bildgenerator (Ngen) durch Microsoft ist ein anderer Ansatz bei der Reduzierung der anfänglichen Verzögerung.[24] NGen-Bytecode in a Gemeinsame Zwischensprache Bild in maschinellen nativen Code. Infolgedessen ist keine Laufzeit -Zusammenstellung erforderlich. .NET Framework 2.0 verschickt mit Visual Studio 2005 Läuft NGen direkt nach der Installation auf allen Microsoft Library DLLs. Pre-Jitting bietet eine Möglichkeit, die Startzeit zu verbessern. Die Qualität des Codes, die er generiert Profilgesteuerte Optimierung, kann nicht so gut sein wie der mit JIT kompilierte Code im extremen Fall: das Fehlen von Profilerierungsdaten zum Beispiel inline -Caching.[25]

Es gibt auch Java -Implementierungen, die eine kombinieren AOT-Compiler (vor der Zeit) mit entweder einem JIT -Compiler (Excelsior Jet) oder Dolmetscher (GNU -Compiler für Java).

Sicherheit

Die JIT -Kompilierung verwendet grundsätzlich ausführbare Daten und stellt somit Sicherheitsherausforderungen und mögliche Aussendungen dar.

Die Implementierung der JIT -Kompilierung besteht darin, Quellcode oder Byte -Code zum Maschinencode zu kompilieren und ihn auszuführen. Dies erfolgt im Allgemeinen direkt im Speicher: Der JIT -Compiler gibt den Maschinencode direkt in den Speicher aus und führt ihn sofort aus, anstatt ihn an die Festplatte auszugeben und dann den Code als separates Programm aufzurufen, wie im Voraus vorab kompiliert. In modernen Architekturen geht dies zu einem Problem aufgrund Ausführbarer Raumschutz: willkürlicher Speicher kann nicht ausgeführt werden, da es sonst ein potenzielles Sicherheitsloch gibt. Somit muss der Speicher als ausführbar markiert werden; Aus Sicherheitsgründen sollte dies getan werden nach Der Code wurde in den Speicher und markiert schreibgeschützt, da beschreibbar/ausführbarer Speicher ein Sicherheitsloch ist (siehe W^x).[26] Zum Beispiel führte der JIT -Compiler von Firefox für JavaScript diesen Schutz in einer Release -Version mit Firefox 46 ein.[27]

JIT -Sprühen ist eine Klasse von Computersicherheit Exploits das verwenden JIT -Kompilierung für Haufensprühen: Der resultierende Speicher ist dann ausführbar, was eine Ausbeutung ermöglicht, wenn die Ausführung in den Haufen verschoben werden kann.

Verwendet

Die JIT -Zusammenstellung kann auf einige Programme angewendet werden oder für bestimmte Kapazitäten verwendet werden, insbesondere für dynamische Kapazitäten wie z. Reguläre Ausdrücke. Beispielsweise kann ein Texteditor einen regulären Ausdruck erstellen, der zur Laufzeit für den Maschinencode bereitgestellt wird, um eine schnellere Übereinstimmung zu ermöglichen: Dies kann nicht im Voraus erfolgen, da das Muster nur zur Laufzeit bereitgestellt wird. Mehrere moderne Laufzeitumgebungen verlassen Java, zusammen mit Microsoft's .NETZ. In ähnlicher Weise verfügen viele reguläre Expressionsbibliotheken mit JIT-Kompilierung regulärer Ausdrücke, entweder zum Bytecode oder zum Maschinencode. Die JIT -Zusammenstellung wird auch in einigen Emulatoren verwendet, um den Maschinencode von einer CPU -Architektur in eine andere zu übersetzen.

Eine gemeinsame Implementierung der JIT -Zusammenstellung besteht darin, zuerst eine AOT -Kompilierung zu Bytecode zu haben (virtuelle Maschine Code), bekannt als Bytecode -Kompilierungund dann eine JIT -Kompilierung zum Maschinencode (dynamische Kompilierung) und nicht die Interpretation des Bytecode. Dies verbessert die Laufzeitleistung im Vergleich zur Interpretation auf Kosten der Verzögerung aufgrund der Zusammenstellung. JIT -Compiler übersetzen kontinuierlich, wie bei Dolmetschern, aber das zwischen kompilierte Code minimiert die Verzögerung bei der zukünftigen Ausführung desselben Code während eines bestimmten Laufs. Da nur ein Teil des Programms zusammengestellt ist, gibt es deutlich weniger Verzögerung als wenn das gesamte Programm vor der Ausführung zusammengestellt wurde.

Siehe auch

Anmerkungen

  1. ^ Vorzeit-Compiler können auch bestimmte Mikroarchitekturen ansprechen, aber der Unterschied zwischen AOT und JIT in dieser Angelegenheit ist die Portabilität. Ein JIT kann den Code, der auf die derzeit laufende CPU zur Laufzeit zugeschnitten ist kann sofort instabil sein.

Verweise

  1. ^ Sprachen, Compiler und Laufzeitsysteme, Universität von Michigan, Informatik und Ingenieurwesen, abgerufen 15. März, 2018
  2. ^ a b c Aycock 2003.
  3. ^ "Nutzt die JIT meine CPU?". David Notarios Weblog. Abgerufen 2018-12-03.
  4. ^ a b Aycock 2003, 2. JIT -Kompilierungstechniken, 2.1 Genesis, p. 98.
  5. ^ McCarthy, J. (April 1960). "Rekursive Funktionen symbolischer Ausdrücke und ihre Berechnung nach Maschine, Teil I". Kommunikation der ACM. 3 (4): 184–195. Citeseerx 10.1.1.111.8833. doi:10.1145/367177.367199. S2CID 1489409.
  6. ^ Thompson 1968.
  7. ^ Aycock 2003, 2. JIT -Kompilierungstechniken, 2.2 LC², p. 98–99.
  8. ^ Mitchell, J.G. (1970). "Das Design und die Konstruktion flexibler und effizienter interaktiver Programmiersysteme". {{}}: Journal zitieren erfordert |journal= (Hilfe)
  9. ^ Deutsch, L.P.; Schiffman, A.M. (1984). "Effiziente Implementierung des SmallTalk-80-Systems" (PDF). Popl '84: Verfahren des 11. ACM Sigact-Sigplan-Symposiums über Prinzipien der Programmiersprachen: 297–302. doi:10.1145/800017.800542. ISBN 0-89791-125-3. S2CID 3045432. Archiviert von das Original (PDF) Am 2004-06-18.
  10. ^ "Archivierte Kopie". Research.sun.com. Archiviert von das Original am 24. November 2006. Abgerufen 15. Januar 2022.{{}}: CS1 Wartung: Archiviertes Kopie als Titel (Link)
  11. ^ Aycock 2003, 2.14 Java, p. 107, Fußnote 13.
  12. ^ "Dynamo: Ein transparentes Dynamikoptimierungssystem". Vasanth Bala, Evelyn Duesterwald, Sanjeev Banerjia. PLDI '00 Proceedings der ACM Sigplan 2000 -Konferenz zum Entwurf und der Implementierung von Programmiersprache. Seiten 1 bis 12. doi 10.1145/349299.349303. Abgerufen am 28. März 2012 abgerufen
  13. ^ John Jannotti. "HPs Dynamo". ARS Technica. Abgerufen 2013-07-05.
  14. ^ "Das HP Dynamo -Projekt". Archiviert vom Original am 19. Oktober 2002. Abgerufen 2016-04-12.{{}}: CS1 Wartung: Ungeeignete URL (Link)
  15. ^ Tung, Liam (27. November 2020). "Programmiersprache PHP 8 ist herausgekommen: Dieser neue JIT -Compiler verweist auf eine bessere Leistung.". ZDNET. Abgerufen 28. November 2020.
  16. ^ Croce, Louis. "Nur in der Zeit Compilation" (PDF). Universität von Columbia. Archiviert von das Original (PDF) Am 2018-05-03.
  17. ^ "Was sind die Vorteile von JIT und AOT -Zusammenstellung". Paketüberfluss. 21. Januar 2010.
  18. ^ "Kompilieren Sie einen JIT -basierten Lang in WebAssembly". Paketüberfluss. Abgerufen 2018-12-04.
  19. ^ Haase, Chet (Mai 2007). "Verbraucher JRE: Leaner, gemeiner Java -Technologie". Sun Microsystems. Abgerufen 2007-07-27.
  20. ^ "Die Java Hotspot Performance Engine Architecture". Oracle.com. Abgerufen 2013-07-05.
  21. ^ Schilling, Jonathan L. (Februar 2003). "Die einfachste Heuristik ist möglicherweise die beste in Java Jit Compilern" (PDF). Sigplan merkt. 38 (2): 36–46. doi:10.1145/772970.772975. S2CID 15117148. Archiviert von das Original (PDF) Am 2015-09-24.
  22. ^ Toshio Suganuma, Toshiaki Yasue, Motohiro Kawahito, Hideaki Komatsu, Toshio Nakatani, "Ein dynamisches Optimierungsrahmen für einen Java-Just-in-Time-Compiler", Verfahren der 16. ACM-Sigplan-Konferenz über objektorientierte Programmierung, Systeme, Sprachen und Anwendungen (Oopsla '01), S. 180–195, 14. bis 18. Oktober 2001.
  23. ^ Matthew Arnold, Michael Hind, Barbara G. Ryder, "Eine empirische Studie zur selektiven Optimierung", Verfahren des 13. Internationalen Workshops über Sprachen und Compiler für parallele Computerpapiere, S. 49–67, 10. bis 12. August 2000.
  24. ^ "Native Bildgenerator (ngen.exe)". Msdn2.microsoft.com. Abgerufen 2013-07-05.
  25. ^ Sweeney, Arnold (Februar 2005). "Eine Umfrage zur adaptiven Optimierung in virtuellen Maschinen" (PDF). Proceedings of the IEEE. 92 (2): 449–466. Archiviert von das Original (PDF) am 2016-06-29.
  26. ^ "How to Jit - Eine Einführung", Eli Bendersky, 5. November 2013 um 5:59 Uhr
  27. ^ De Mooij, Jan. "W^x JIT-Code in Firefox aktiviert". Jan de Mooij. Abgerufen 11. Mai 2016.

Weitere Lektüre

Externe Links