ART-Just-in-Time-Compiler implementieren

Die Android-Laufzeit (Android Runtime, ART) enthält einen Just-in-Time-Compiler (JIT) mit Code-Profiling, der die Leistung von Android-Anwendungen während der Ausführung kontinuierlich verbessert. Der JIT-Compiler ergänzt den aktuellen Ahead-of-Time-Compiler (AOT) von ART und verbessert die Laufzeitleistung, spart Speicherplatz und beschleunigt Anwendungs- und Systemupdates. Außerdem wird der AOT-Compiler verbessert, da das System bei automatischen App-Updates oder der Neukompilierung von Apps bei OTA-Updates (Over-the-Air) nicht verlangsamt wird.

Obwohl JIT und AOT denselben Compiler mit einer ähnlichen Reihe von Optimierungen verwenden, ist der generierte Code möglicherweise nicht identisch. JIT nutzt Laufzeittypinformationen, kann Inlining besser durchführen und ermöglicht die OSR-Kompilierung (On-Stack Replacement), was alles zu leicht unterschiedlichem Code führt.

JIT-Architektur

JIT-Architektur
Abbildung 1. JIT-Architektur

JIT-Kompilierung

Die JIT-Kompilierung umfasst die folgenden Aktivitäten:

Profilgesteuerte Kompression
Abbildung 2. Profilgesteuerte Kompilierung
:
  1. Der Nutzer führt die App aus, wodurch ART die .dex-Datei lädt.
    • Wenn die Datei .oat (das AOT-Binärprogramm für die Datei .dex) verfügbar ist, verwendet ART sie direkt. .oat-Dateien werden zwar regelmäßig generiert, enthalten aber nicht immer kompilierten Code (AOT-Binärdatei).
    • Wenn die Datei .oat keinen kompilierten Code enthält, führt ART JIT und den Interpreter aus, um die Datei .dex auszuführen.
  2. JIT ist für alle Anwendungen aktiviert, die nicht gemäß dem Kompilierungsfilter speed kompiliert werden (der besagt, dass so viel wie möglich aus der App kompiliert werden soll).
  3. Die JIT-Profildaten werden in eine Datei in einem Systemverzeichnis geschrieben, auf das nur die Anwendung zugreifen kann.
  4. Der Daemon für die AOT-Kompilierung (dex2oat) parst diese Datei, um die Kompilierung zu steuern.

    JIT-Daemon
    Abbildung 3: JIT-Daemon-Aktivitäten.

Der Google Play-Dienst ist ein Beispiel für eine Anwendung, die sich ähnlich wie gemeinsam genutzte Bibliotheken verhält.

JIT-Workflow

JIT-Architektur
Abbildung 4: JIT-Datenfluss
  • Profiling-Informationen werden im Code-Cache gespeichert und bei Speichermangel der Garbage Collection unterzogen.
    • Es gibt keine Garantie dafür, dass ein Snapshot, der aufgenommen wurde, als sich die Anwendung im Hintergrund befand, vollständige Daten enthält (d.h. alles, was JIT-kompiliert wurde).
    • Es wird nicht versucht, alles aufzuzeichnen, da dies die Laufzeitleistung beeinträchtigen kann.
  • Methoden können drei verschiedene Status haben:
    • interpretiert (DEX-Code)
    • JIT-kompiliert
    • AOT-kompiliert
    Wenn sowohl JIT- als auch AOT-Code vorhanden ist (z.B. aufgrund wiederholter Deoptimierungen), wird der JIT-Code bevorzugt.
  • Der Speicherbedarf für die Ausführung von JIT, ohne die Leistung der Vordergrund-App zu beeinträchtigen, hängt von der jeweiligen App ab. Große Apps benötigen mehr Arbeitsspeicher als kleine Apps. Im Allgemeinen stabilisieren sich große Apps bei etwa 4 MB.

JIT-Protokollierung aktivieren

Führen Sie die folgenden Befehle aus, um die JIT-Protokollierung zu aktivieren:

adb root
adb shell stop
adb shell setprop dalvik.vm.extra-opts -verbose:jit
adb shell start

JIT deaktivieren

Führen Sie die folgenden Befehle aus, um JIT zu deaktivieren:

adb root
adb shell stop
adb shell setprop dalvik.vm.usejit false
adb shell start

Kompilierung erzwingen

Führen Sie Folgendes aus, um die Kompilierung zu erzwingen:

adb shell cmd package compile

Häufige Anwendungsfälle für das Erzwingen der Kompilierung eines bestimmten Pakets:

  • Profilbasiert:
    adb shell cmd package compile -m speed-profile -f my-package
    
  • Vollständig:
    adb shell cmd package compile -m speed -f my-package
    

Häufige Anwendungsfälle für das Erzwingen der Kompilierung aller Pakete:

  • Profilbasiert:
    adb shell cmd package compile -m speed-profile -f -a
    
  • Vollständig:
    adb shell cmd package compile -m speed -f -a
    

Profildaten löschen

Android 13 oder niedriger

Führen Sie Folgendes aus, um lokale Profildaten zu löschen und kompilierten Code zu entfernen:

adb shell pm compile --reset 

Android 14 oder höher

So löschen Sie nur lokale Profildaten:

adb shell pm art clear-app-profiles 

Hinweis: Im Gegensatz zum Befehl für Android 13 oder niedriger werden mit diesem Befehl keine externen Profildaten (`.dm`) gelöscht, die mit der App installiert wurden.

Wenn Sie lokale Profildaten löschen und kompilierten Code entfernen möchten, der aus lokalen Profildaten generiert wurde (d.h. auf den Installationsstatus zurücksetzen), führen Sie Folgendes aus:

adb shell pm compile --reset 

Hinweis: Mit diesem Befehl wird kein kompilierter Code entfernt, der aus externen Profildaten (`.dm`) generiert und mit der App installiert wurde.

Führen Sie den folgenden Befehl aus, um den gesamten kompilierten Code zu löschen:

adb shell cmd package compile -m verify -f 

Hinweis: Bei diesem Befehl werden lokale Profildaten beibehalten.