JIT: Was ist Just-In-Time-Kompilierung und wie funktioniert sie

Autor: IT Sectr Veröffentlicht: 2026-04-16 Lesezeit: 9 Min.

JIT (Just-In-Time) ist eine dynamische Kompilierungstechnologie, die Bytecode oder eine Zwischendarstellung eines Programms direkt während der Ausführung in Maschinenanweisungen umwandelt. In Android erschien der JIT-Compiler erstmals in Version 2.2 Froyo als Teil der virtuellen Maschine Dalvik und beschleunigte die Ausführung von Anwendungen um das 2–5-fache. Laut Google, 2024 kombiniert der moderne JIT in ART die Interpretation mit der profilierten Kompilierung von heißen Methoden.

Wichtige Erkenntnisse

  • JIT — Just-In-Time-Kompilierung: Umwandlung von Code in Maschinencode direkt während der Programmausführung.
  • In Dalvik kompilierte JIT heiße Methoden nach Überschreiten der Aufrufschwelle (~200 Mal).
  • JIT reduziert die Installationszeit und benötigt weniger Speicherplatz als eine vollständige AOT-Kompilierung.
  • Der Hauptnachteil ist die Aufwärmverzögerung: In den ersten Sekunden läuft die Anwendung langsamer.
  • Im modernen ART wird JIT in einem Hybridmodus mit AOT-Optimierung im Hintergrund verwendet.

Was ist JIT-Kompilierung?

Just-In-Time (JIT) ist eine Kompilierungsmethode, bei der Quellcode oder Bytecode nicht im Voraus (wie bei AOT), sondern zum Zeitpunkt des ersten Aufrufs des entsprechenden Programmabschnitts in Maschinenanweisungen umgewandelt wird. Der Begriff „Just-In-Time“ bedeutet, dass die Kompilierung „gerade rechtzeitig“ erfolgt — unmittelbar vor der Ausführung.

Das Konzept von JIT existiert seit den 1960er Jahren, fand jedoch mit dem Aufkommen der Java Virtual Machine im Jahr 1995 breite Akzeptanz. JIT ermöglicht die Kombination der Portabilität von Bytecode (einmal schreiben — überall ausführen) mit einer Leistung nahe an nativem Code. In der Java HotSpot VM analysiert der JIT-Compiler den ausgeführten Code und kompiliert nur die kritischsten Abschnitte, wodurch Zeit und Speicher gespart werden.

Funktionsweise

Der JIT-Compiler erhält Bytecode als Eingabe, interpretiert ihn und sammelt gleichzeitig Statistiken. Wenn ein bestimmter Codeabschnitt (Methode, Schleife) häufig genug aufgerufen wird, entscheidet JIT, ihn zu kompilieren. Der kompilierte Maschinencode wird in einem Cache gespeichert — bei nachfolgenden Aufrufen wird die bereits kompilierte Version verwendet. Dies bietet eine Beschleunigung, ohne das gesamte Programm kompilieren zu müssen.

java
// Beispiel: Eine Methode wird nach mehreren Aufrufen heiß
public class HotMethod {
    private int compute(int n) {
        int sum = 0;
        for (int i = 0; i < n; i++) {
            sum += i * i;
        }
        return sum;
    }
}

// 500-mal in einer Schleife aufrufen — JIT wird compute kompilieren
for (int t = 0; t < 500; t++) {
    hot.compute(1000);
}

JIT in Android: Dalvik und ART

In Android durchlief die JIT-Kompilierung drei Evolutionsphasen. Die erste Phase — Dalvik ohne JIT (Android 1.0–2.1): reine Interpretation von DEX-Bytecode. Die zweite Phase — Dalvik mit JIT (Android 2.2–4.4): Einführung des JIT-Compilers, der Anwendungen um das 2–5-fache beschleunigte. Die dritte Phase — ART mit hybridem JIT (Android 7.0+): die Rückkehr von JIT in einer neuen Funktion.

JIT in Dalvik wurde als trace-basierter Compiler implementiert. Er analysierte nicht einzelne Methoden, sondern Befehlsketten (Traces), die häufig sequenziell ausgeführt werden. Dies ermöglichte die Kompilierung vollständiger Ausführungspfade einschließlich mehrerer Methoden. Dieser Ansatz war effektiv für mobile Prozessoren mit kleinen Befehlscaches, da der kompilierte Trace in den L1-Cache passte.

JIT im modernen ART

Ab Android 7.0 Nougat verwendet ART methodenbasiertes JIT — es kompiliert einzelne Methoden basierend auf Ausführungsprofilen. Dieses JIT arbeitet deutlich schneller als Dalvik JIT: Die typische Kompilierungszeit für eine Methode beträgt 0.5–1 ms gegenüber 3–5 ms in Dalvik. Der kompilierte Code wird in einem separaten Speicherbereich (JIT-Code-Cache) und nicht im Anwendungs-Heap gespeichert, was die Fragmentierung reduziert.

ParameterDalvik JITART JIT
TypTrace-basiertMethodenbasiert
Kompilierungsgeschwindigkeit3–5 ms/Methode0.5–1 ms/Methode
Kompilierungsschwelle~200 AufrufeDynamisch
Code-CacheIm Anwendungs-HeapJIT-Code-Cache
ProfilierungInternExterne .prof-Dateien

Erkennung heißer Methoden und Kompilierungsschwellen

Der zentrale Mechanismus von JIT ist die Erkennung heißer Methoden. Jeder Methodenaufruf erhöht einen internen Zähler. Wenn der Zähler die Schwelle überschreitet, wird die Methode als „heiß“ markiert und zur Kompilierung gesendet. In Dalvik war die Schwelle festgelegt (~200 Aufrufe). In ART werden die Zähler dynamisch in Abhängigkeit von den verfügbaren Ressourcen des Geräts konfiguriert.

Der Kompilierungsprozess umfasst mehrere Phasen. Die erste — Bytecode-Analyse: JIT untersucht den Befehlsstrom und erstellt einen Datenflussgraphen. Die zweite — Optimierung: Inlining kleiner Methoden, Entfernung von totem Code, Konstantenfaltung. Die dritte — Codegenerierung: Umwandlung des optimierten Graphen in Maschinenanweisungen für eine bestimmte CPU-Architektur (ARM, ARM64, x86).

java
// Demonstration von Inlining — JIT wird den Methodenrumpf einbetten
public int inlineExample() {
    return square(5);
}

private int square(int x) {
    return x * x;
} // JIT wird den Aufruf durch return 5 * 5; ersetzen

OSR — On-Stack Replacement

Eine spezielle JIT-Technik — On-Stack Replacement (OSR). Wenn eine Methode eine lange Schleife enthält, die über Hunderte von Iterationen nicht endet, kann JIT die Schleife „im laufenden Betrieb“ kompilieren und die interpretierte Version direkt während der Ausführung durch die kompilierte ersetzen. OSR ist besonders effektiv für rechenintensive Aufgaben: Rendering, Bildverarbeitung, Kryptographie.

JIT vs AOT: Vergleichende Analyse

JIT und AOT sind zwei Kompilierungsansätze mit gegensätzlichen Kompromissen. JIT opfert die Geschwindigkeit des ersten Starts für eine kompakte Distributionsgröße und Anpassungsfähigkeit. AOT opfert Installationszeit und Speicherplatz für maximale Leistung von der ersten Sekunde an. Keiner der Ansätze ist absolut besser — die Wahl hängt vom Szenario ab.

Der Hauptvorteil von JIT ist die adaptive Optimierung. JIT kann Profilinformationen nutzen, die AOT nicht zur Verfügung stehen: genaue Objekttypen, tatsächliche Aufruffrequenz, tatsächliche Verzweigungsmuster. Dies ermöglicht aggressive Optimierungen, die bei statischer Kompilierung unmöglich sind. Beispielsweise kann JIT Methodenaufrufe devirtualisieren, wenn in der Praxis nur ein Empfängertyp vorkommt.

KriteriumJITAOT
InstallationszeitSofortAbhängig von der Größe
Erster StartLangsamer (Aufwärmen)Schnell
SpeicherplatzMinimal+15–30%
AnpassungsfähigkeitHochNiedrig
CPU-AuslastungSpitzen bei KompilierungStabil

Wann man JIT wählen sollte

JIT-Kompilierung ist vorzuziehen, wenn eine schnelle Bereitstellung und Speicherplatzersparnis wichtig sind. Im Kontext der mobilen Entwicklung ist JIT ideal für Anwendungen, die häufig aktualisiert werden (A/B-Tests, Hotfixes). JIT ist auch während der Entwicklung praktisch, wenn Code dutzende Male am Tag neu erstellt wird — jede bei der Kompilierung eingesparte Sekunde beschleunigt die Rückkopplungsschleife.

Vorteile der JIT-Kompilierung

JIT bietet Entwicklern eine Reihe praktischer Vorteile. Der erste — kleine APK-Größe. Beim JIT-Ansatz wird nur Bytecode (DEX) in die APK verpackt, der 20–30% weniger Platz benötigt als kompilierter nativer Code. Für Benutzer mit begrenztem internen Speicher ist dies ein bedeutender Vorteil.

Der zweite Vorteil ist die Geräteanpassung. JIT kompiliert Code unter Berücksichtigung der tatsächlichen CPU-Architektur, der RAM-Größe und der aktuellen Last. Beispielsweise kann JIT auf einem Gerät mit 2 GB RAM weniger aggressiv kompilieren, um Speicher zu sparen, während es auf einem Flaggschiff mit 12 GB alle möglichen Optimierungen anwenden kann. Die AOT-Kompilierung hingegen fixiert die Entscheidung zum Zeitpunkt der Installation.

Plattformunabhängigkeit

Bytecode bleibt plattformunabhängig, was die Verteilung von Anwendungen vereinfacht. Eine APK funktioniert auf ARM-, ARM64- und x86-Geräten, und JIT generiert nativen Code für jede Architektur. Der AOT-Ansatz würde entweder das Einfügen mehrerer nativer Code-Varianten in die APK (Größensteigerung) oder das Kompilieren einer separaten Version für jede Architektur erfordern.

Nachteile und Einschränkungen von JIT

Der Hauptnachteil von JIT ist die Aufwärmverzögerung. Der Benutzer erlebt Verlangsamungen in den ersten Sekunden der Anwendung, während JIT heiße Methoden kompiliert. In Spielen äußert sich dies als Ruckeln in den Anfangsleveln. In Anwendungen mit Animationen — ruckartige erste Übergänge zwischen Bildschirmen.

Der zweite Nachteil — Energieverbrauch. Der Kompilierungsprozess belastet die CPU stark und erhöht den Energieverbrauch während der Aufwärmphase um 10–20%. Bei batteriebetriebenen Geräten verkürzt dies die Akkulaufzeit. Besonders bemerkbar ist dies in Szenarien mit häufigen Anwendungsneustarts (Multitasking mit begrenztem Speicher, bei dem das System Prozesse entlädt und neu lädt).

Cache-Fragmentierung

Ein weiteres Problem — die JIT-Cache-Fragmentierung. Der kompilierte Code wird in einem kontinuierlichen Speicherbereich gespeichert. Wenn neue Klassen geladen und zusätzliche Methoden kompiliert werden, fragmentiert der Cache, was den Speicherverwaltungsaufwand erhöht. In Dalvik wurde dieses Problem durch regelmäßiges Cache-Leeren gelöst; in ART wird der JIT-Cache getrennt vom Heap zugewiesen und verwendet eine eigene Defragmentierungsstrategie.

Hybridmodus: Das Beste aus beiden Welten

Der moderne Ansatz in ART — die hybride Kompilierung, die die Stärken von JIT und AOT vereint. Während der Installation der Anwendung wird keine Kompilierung durchgeführt — nur die Bytecode-Überprüfung (Verify). Dies gewährleistet eine schnelle Installation und minimale Speichernutzung. Die ersten Starts erfolgen im Interpretationsmodus mit JIT-Kompilierung heißer Methoden — der Benutzer erhält eine akzeptable Leistung ohne lange Wartezeiten.

Parallel dazu sammelt ein Hintergrundprofiler Daten über die tatsächliche Nutzung. Nach 2–3 vollständigen Anwendungsstarts erreicht das Profil ausreichende Vollständigkeit, und das System startet dex2oat, um heiße Methoden in nativen Code zu kompilieren. Diese Operation wird im Hintergrund ausgeführt, wenn das Gerät nicht ausgelastet ist (Laden, Bildschirm aus). Nach Abschluss der Hintergrund-AOT erreicht die Anwendung eine Leistung, die mit der vollständigen AOT-Kompilierung vergleichbar ist.

bash
# Erzwungener Start der Hintergrundkompilierung
adb shell cmd package compile -m speed-profile -f com.example.app

# Kompilierungsstatus anzeigen
adb shell cmd package dump-profiles com.example.app

Ergebnisse des hybriden Ansatzes

Laut Google I/O 2017 reduzierte die hybride Kompilierung die Installationszeit von Anwendungen um 30–50% im Vergleich zu reinem AOT. Der belegte Speicherplatz auf der Systempartition verringerte sich um 20–30%. Gleichzeitig entspricht die Leistung nach der Hintergrundkompilierung dem Niveau der vollständigen AOT. Das einzige Szenario, in dem der Hybrid AOT unterlegen ist, ist der erste Start unmittelbar nach der Installation: Die Anwendung läuft im JIT-Modus und kann 10–15% langsamer sein.

Häufig gestellte Fragen

Was ist JIT-Kompilierung in einfachen Worten?

JIT ist eine Möglichkeit, ein Programm zu beschleunigen, bei der Code nicht im Voraus, sondern während der Laufzeit in Teilen in Maschinensprache übersetzt wird. Die häufigsten Abschnitte werden kompiliert und zwischengespeichert, während seltene in ihrer ursprünglichen Form bleiben.

Wie unterscheidet sich JIT von AOT?

JIT kompiliert Code während der Ausführung, spart Speicherplatz und beschleunigt die Installation. AOT kompiliert den gesamten Code im Voraus — die Anwendung startet schneller, benötigt aber mehr Speicherplatz und Installationszeit.

Warum wurde JIT aus Android entfernt?

JIT wurde nicht entfernt, sondern weiterentwickelt. In Android 5.0 wurde Dalvik mit JIT durch ART mit reinem AOT ersetzt. In Android 7.0 kehrte JIT als Teil eines hybriden Systems zu ART zurück, wo es für optimale Leistung mit der Hintergrund-AOT-Kompilierung zusammenarbeitet.

Wie wirkt sich JIT auf den Energieverbrauch aus?

JIT erhöht den Energieverbrauch während der Aufwärmphase aufgrund der CPU-Last um 10–20%. Nach Abschluss der Kompilierung heißer Methoden normalisiert sich der Energieverbrauch wieder. Der Hybridmodus von ART minimiert diese Spitzen durch Hintergrundkompilierung.

Ist das JIT-Aufwärmen für den Benutzer sichtbar?

Ja, in Szenarien mit intensiven Berechnungen. Der Benutzer kann in den ersten Sekunden des Anwendungsbetriebs oder zu Beginn eines Spiels Verlangsamungen bemerken. In modernen Android-Versionen (8.0+) minimiert der Hybridmodus diesen Effekt dank der profilierten Kompilierung.

Zusammenfassung

  • JIT (Just-In-Time) ist eine dynamische Kompilierung, die Bytecode während der Ausführung in Maschinenanweisungen umwandelt.
  • In Android entwickelte sich JIT weiter: trace-basiert in Dalvik → vollständige AOT → hybrides JIT+AOT im modernen ART.
  • Heiße Methoden werden durch Aufrufzähler erkannt und bei Überschreiten der Schwelle (~200 Aufrufe) kompiliert.
  • OSR (On-Stack Replacement) ermöglicht die Kompilierung langer Schleifen im laufenden Betrieb ohne Unterbrechung der Ausführung.
  • Hauptvorteile von JIT: kleine APK-Größe, schnelle Installation und Geräteanpassung.
  • Hauptnachteile: Aufwärmverzögerung, Spitzenenergieverbrauch und Cache-Fragmentierung.
  • Der ART-Hybridmodus (Android 7.0+) reduziert die Installationszeit um 30–50% bei gleichbleibend hoher Leistung.

Wir entwickeln eine mobile Applikation schlüsselfertig

IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.

Projekt besprechen

Lesen Sie auch