Diskussion:Just-in-time-Kompilierung
Auf dieser Seite werden Abschnitte ab Überschriftenebene 2 automatisch archiviert, die seit 30 Tagen mit dem Baustein {{Erledigt|1=--~~~~}} versehen sind. Das aktuelle Archiv befindet sich unter Diskussion:Just-in-time-Kompilierung/Archiv. |
Keine Quellen
BearbeitenInsbesondere für die Behauptung "Hochentwickelte JIT-Compiler können speziell für dynamische Sprachen schnelleren Code als herkömmliche Compiler generieren, da sie Closed-World-Annahmen treffen können und Dynamische Optimierungen durchführen." gibt es doch sicherlich konträre Aussagen. (nicht signierter Beitrag von 77.187.33.99 (Diskussion | Beiträge) 14:21, 16. Mär. 2010 (CET))
- Nein, weil's "konträr" kaum geht. Z.B. kann es sein, dass durch Benutzereingaben während des Programmablaufs bestimmte Fälle/Programmteile (endgültig) ausgeschlossen werden können und 100%-ig nicht mehr zur Ausführung kommen. Wenn z.B. im Hauptprogramm die Variable A (dynamische Typbindung!) auf eine Ganzzahl gesetzt wird, und der Programmteil, der sie zu einem Text(!) umsetzen würde, 100%-ig nicht mehr ausgeführt wird, dann kann A als statisch-INT kompiliert werden. Ein Vorab-Compiler müsste verschiedene Programmversionen erstellen, je nach dem, welche "kritischen" Programmteile u.U. ausgeschlossen werden könnten. Bei 10 solcher Programmteile ergibt das dann 2^10 = 1024 verschiedene Programmversionen... --arilou 14:34, 15. Feb. 2011 (CET)
Closed-World-Annahmen
BearbeitenWarum können AOT-Compiler keine Closed-World-Annahmen machen bzw. inwiefern haben JIT-Compiler dafür bessere Voraussetzungen? Kann jemand ein Beispiel nennen. Oder betrifft das die selben Aspekte wie die dynamischen Optimierungen? (nicht signierter Beitrag von Croorg (Diskussion | Beiträge) 16:33, 11. Mär. 2008 (CET))
- Ja ich denke, damit ist die dynamische Optimierung gemeint. MetalTux 12:20, 25. Jun. 2010 (CEST)
- Auch, aber nicht nur. (Siehe mein Beispiel oben.) --arilou 14:36, 15. Feb. 2011 (CET)
Unterschied zur Interpretation
Bearbeitenwird nicht deutlich: Auch bei der Interpretation muss Maschinencode erzeugt werden.--Biktora 20:10, 6. Mär. 2010 (CET)
- Der Unterschied liegt im Zeitpunkt, zu dem der Maschinencode erzeugt wird. Ein Interpreter ist in der Regel als "Message Pump" implementiert, zentraler Bestandteil ist also eine Schleife, die mit einem Befehlszähler über den auszuführenden Code (zeilenweise bei einem Quelltext-Interpreter oder opcodeweise bei einem Bytecode-Interpreter) läuft und dann (in der Regel über eine Jumptable) die jeweils zuständigen "Instruction Handler" aufruft, die dann die Operationen auf der Zielmaschine in Gang bringen, die notwendig sind, um den Befehl auszuführen, der interpretiert werden soll. Dieser "Instruction Handler" ist selbst Bestandteil des (Hochsprachen-)Codes des Interpreters, wird also schon bei der Übersetzung des Interpreters zu Maschinencode und ist danach mehr oder weniger unveränderlich. Einen JIT-Compiler wird man in der Regel auch als "Message Pump" aufbauen, nur sehen dann die "Instruction Handler" eben anders aus. Da ist dann nicht codiert, wie der Befehl ausgeführt werden soll, sondern wie man Maschinencode erzeugt, der den Befehl ausführt. Wichtig ist, dass der Code erst erzeugt wird, wenn der Instruction-Handler tatsächlich aufgerufen wird, während er beim Interpreter schon bei der Compilierung "hart" in's Executable Image wandert und darauf wartet, aufgerufen zu werden. Nachdem der JIT-Compiler den (Maschinen-)Code erzeugt hat, der zur Ausführung notwendig ist, setzt er den Befehlszähler der CPU auf den Anfang des gerade generierten Codes, sodass er ausgeführt wird. Am Ende wird dann in die "Message Loop" des JIT-Compilers zurückgesprungen, damit er die nächste Anweisung laden und compilieren kann. MetalTux 12:20, 25. Jun. 2010 (CEST)
- Soweit ich weis, wird beim Interpreter überhaupt kein Maschinencode erzeugt - zumindest nicht für das (zu interpretierende) Anwendungsprogramm. Maschinencode entstand, als der Interpreter seinerseits compiliert wurde.
- "Instruction Handler aufruft, die dann die Operationen auf der Zielmaschine in Gang bringen, die notwendig sind, um den Befehl auszuführen, der interpretiert werden soll" ~ ziemlich verklausuliert ;-) . Der Instuction Handler vor "seiner" Maschinencode-Routine ist/realisiert den zu interpretierenden Befehl.
- Deine Erläuterung zum JIT-Compiler-Aufbau über "Message Pump", hm, da wär' ich mir nicht so sicher. Das würde jegliche Optimierung verhindern, insbesondere Befehls-übergreifende. Ansonsten könnte man so ziemlich jeden Compiler als "Message Pump" auffassen...
- Man könnte aus deiner Erklärung schließen, jeder Token/Zeile der Anwendung werde getrennt kompiliert, jeweils wenn die Ausführung darauf trifft. Afaik werden aber immer "Blöcke" kompiliert, z.T. auch erst beim 2. oder 3. Mal Ausführung (vorher wird interpretiert). Außerdem wird einmal kompiliertes beibehalten, um nicht erneut kompilieren zu müssen.
- --arilou 14:57, 15. Feb. 2011 (CET)
- Genau, beim Interpretieren wird kein Maschinencode erzeugt, aber der Interpreter liegt selbst in Maschinencode vor und enthält schon "Instruction Handler" genannte Routinen, welche für jeden zu interpretierenden Befehl/Token Maschinencode enthalten, der direkt ausgeführt werden kann. Die ganze "Codegenerierung" ist also schon zu dem Zeitpunkt passiert, zu dem der Interpreter selbst compiliert wurde und ist daher zur Laufzeit nicht mehr nötig (drum haben interpretierte Anwendungen in der Regel ein geringeres "Startup Delay", als JIT-compilierte).
- Bei den anderen Punkten muss man jetzt differenzieren, das fängt schon bei "kompiliertes beibehalten" an. Streng genommen sagt der Begriff JIT-Compiler nur aus, dass der Code zur Laufzeit übersetzt wird (dass eben ein "Compiler läuft", während die Software ausgeführt wird). In der Praxis wird man den Code fast immer aufheben, um ihn nicht nochmal Compilieren zu müssen, aber es wäre auch eine Implementierung denkbar (wenn auch nicht sonderlich sinnvoll), die es anders macht und das wäre dann per Definition immernoch ein JIT-Compiler.
- Auch das Compilieren in "Blöcken" ist so eine Sache. Es sind auch Compiler denkbar, die das Programm direkt vor der Ausführung komplett übersetzen und den erzeugten Code dann im RAM halten (wobei man dieses Vorgehen eigentlich auch noch als Grenzfall der AOT-Compilierung auffassen könnte, bei der lediglich kein Output auf die Platte wandert) und genauso sind Compiler denkbar, die jede Instruction einzeln übersetzen (ich hatte einen solchen sogar mal implementiert, allerdings nur als erste von unzählig vielen "Stufen" in einem Code-Optimizer, es war also nicht so, dass der Output da direkt zur Ausführung gekommen wäre ;-) ).
- So viel nur zur Erläuterung. Ich finde was momentan im Artikel steht beschreibt den Sachverhalt ganz treffend, auch wenn der Artikel immernoch recht kurz ist.
- Die Performancesteigerung gegenüber Interpretern muss man übrigens relativieren. Da der Code des Interpreters ja selbst Maschinencode ist und effektiv nur Sprünge in Instruction-Handler durchgeführt werden (die in der Regel selbst sehr stark "von Hand" durch den Entwickler des Interpreters auf Performance optimiert wurden) ist das so eine Sache. Ein JIT lohnt sich eigentlich erst, wenn signifikante Teile des Codes häufig durchlaufen werden (z. B. weil sie Schleifen, evtl. sogar geschachtelte Schleifen, oder Rekursion enthalten). Bei Code, der einfach "linear durchlaufen" wird und eine vorgegebene Berechnungsvorschrift ausführt, wird das Interpretieren meistens sogar (wesentlich) schneller sein (das JIT-Compilieren dauert schließlich auch seine Zeit). Deshalb gibt es HotSpot-Compiler (diese Technik wurde von Sun erfunden soweit ich mich erinnern kann), die nur häufig durchlaufene Abschnitte compilieren (wie Arilou schon beschrieben hatte). Das ist aber ebenfalls ein besonderes Merkmal von JIT-Compilern, das z. B. der JIT-Compiler enthält, der in der Java Virtual Machine von Sun zum Einsatz kommt. Es gibt auch viele JIT-Engines, die dieses Merkmal nicht enthalten und immer sofort compilieren (das "Virtual Execution System" des Microsoft .NET Frameworks wäre eine solche Engine). MetalTux 18:05, 22. Feb. 2011 (CET)
- Ich zitier' mal die Wiki-Tugend: "Sei mutig!" - und schreib' vieles statt in die Disku- in die Artikel-Seite ;-) --129.247.247.238 15:21, 23. Feb. 2011 (CET)
JIT-Compiler übersetzt immer in Maschinencode?
BearbeitenKann ein JIT-Compiler nicht auch den Code einer VM in den Code einer anderen VM übersetzen? Mir fällt da gerade IKVM ein, der Java Bytecode in Common Intermediate Language übersetzt und ihn anschließend auf der Common Language Infrastructure ausführen lässt. Würde das nicht unter den Begriff "JIT-Compiler" fallen? MetalTux 12:20, 25. Jun. 2010 (CEST)
- Ich kenne diesen IKVM nicht, aber, sofern der Java-Bytecode auch interpretiert laufen könnte, stimme ich zu. Der Java-Bytecode müsste also in einer VM/Interpreter laufen, der seinerseits ein CLI-Programm ist, und Teile des Java-Progis JIT zu CLI-Code compiliert. --arilou 15:19, 23. Feb. 2011 (CET)
Android mit JIT
BearbeitenAndroid besitzt/unterstützt ab Version 2.2 JIT, siehe http://de.wikipedia.org/wiki/Liste_von_Android-Versionen . Sollte das erwähnt werden? --MichaelK-osm (Diskussion) 17:56, 10. Sep. 2012 (CEST)
Python, Javascript,...
BearbeitenJavascript, Python und ko sind doch Skriptsprachen und werden interpretiert, was hat das mit Compilierung zu tun? (nicht signierter Beitrag von 2001:638:904:FFC7:387C:B0BD:1510:DF9C (Diskussion | Beiträge) 20:24, 29. Okt. 2013 (CET))
- Da solltest du dich nochmal schlau machen - interpretieren war gestern. --arilou (Diskussion) 09:46, 30. Okt. 2013 (CET)
Edit War um Ausführungsgeschwindigkeit
BearbeitenIch habe folgenden Absatz mit der Begründung "unbelegt und falsch - Ausführungsgeschwindigkeit von JIT ist häufig schneller - siehe Optimierungsmöglichkeiten" entfernt:
- Die Ausführungsgeschwindigkeit der VM entspricht einem Interpreter und ist häufig langsamer im Vergleich zu nativ kompilierten Programmen, welche aus direkt durch den Prozessor ausführbaren Instruktionen bestehen. Durch Just-in-time-Kompilierung versucht man, diesen Nachteil auszugleichen.
@Benutzer:Arilou hat sie mit der Begründung "langsam ist die Interpreter-Abarbeitung durch eine VM; über die Geschw. des JIT-Compiler-Ergebnisses wird (direkt) nichts gesagt." wieder reingegeben.
- belegt ist die Aussage weiterhin nicht
- die Ausführungsgeschwindigkeit der VM entspricht nicht der eines Interpreters:
- entweder ist damit die Ausführung der VM selbst gemeint, diese ist aber 1:1 dieselbe wie die jedes anderen compilierten Programmes, ein Maschinenbefehl nach dem anderen.
- oder es ist damit die Ausführung des Codes durch die VM gemeint, dann entspricht sie nur dann der eines Interpreters, wenn die VM nicht JIT oder sonstige Optimierungen macht (also keine VM, sondern ein Interpreter wäre)
- oder es ist damit die Ausführungsgeschwindigkeit des Programmes durch die VM gemeint, dann stimmts schon gar nicht, da das eben wie gesagt auch deutlich schneller sein kann als bei einem compilierten Programm
also bitte erstens klarer schreiben was denn jetzt langsamer ist und zweitens belegen. --Sebastian.Dietrich ✉ 00:40, 28. Jan. 2016 (CET)
- Es wird in dem Satz/Abschnitt zwischen zwei Situationen unterschieden:
- Ausführung von VM-Bytecode ohne JIT-Kompilierung versus
- Ausführung von VM-Bytecode mit JIT-Kompilierung.
(Zitat: "Durch Just-in-time-Kompilierung versucht man, diesen Nachteil auszugleichen." - also gibt es eine Situation vor/ohne JIT-Komp. mit Nachteilen, und eine Situation nach/mit JIT-Komp., die die Nachteile lindern/ausgleichen soll.
- Eine VM ohne JIT-Komp. ist folglich ein Bytecode-Interpreter, i.A. auch ohne irgend eine weitere Optimierung.
Ist diesbezüglich noch strittig (und zu belegen), ob/dass solch ein Interpreter i.A. langsamer als eine VM mit JIT-Kompilierung ist?
- Es wird in dem Satz/Abschnitt zwischen zwei Situationen unterschieden:
- --arilou (Diskussion) 08:56, 28. Jan. 2016 (CET)