Implementazione del compilatore just-in-time ART

Android Runtime (ART) include un compilatore just-in-time (JIT) con profilazione del codice che migliora continuamente le prestazioni delle applicazioni Android durante l'esecuzione. Il compilatore JIT integra l'attuale compilatore ahead-of-time (AOT) di ART e migliora le prestazioni di runtime, consente di risparmiare spazio di archiviazione e velocizza gli aggiornamenti di applicazioni e sistema. Migliora anche il compilatore AOT evitando il rallentamento del sistema durante gli aggiornamenti automatici delle applicazioni o la ricompilazione delle applicazioni durante gli aggiornamenti over-the-air (OTA).

Sebbene JIT e AOT utilizzino lo stesso compilatore con un insieme simile di ottimizzazioni, il codice generato potrebbe non essere identico. JIT utilizza informazioni sul tipo di runtime, può eseguire un'incorporazione migliore e rende possibile la compilazione OSR (On Stack Replacement), il che genera un codice leggermente diverso.

Architettura JIT

Architettura JIT
Figura 1. architettura JIT.

Compilazione JIT

La compilazione JIT prevede le seguenti attività:

Compilazione guidata dal profilo
Figura 2. Compilazione guidata dal profilo.
  1. L'utente esegue l'app, che a sua volta attiva ART per caricare il file .dex.
    • Se il file .oat (il binario AOT per il file .dex ) è disponibile, ART lo utilizza direttamente. Sebbene i file .oat vengano generati regolarmente, non sempre contengono codice compilato (binario AOT).
    • Se il file .oat non contiene codice compilato, ART esegue JIT e l'interprete per eseguire il file .dex.
  2. La compilazione JIT è attivata per qualsiasi applicazione non compilata in base al filtro di compilazione speed (che indica "compila il più possibile dall'app").
  3. I dati del profilo JIT vengono scaricati in un file in una directory di sistema a cui può accedere solo l'applicazione.
  4. Il daemon di compilazione AOT (dex2oat) analizza il file per guidare la compilazione.

    Daemon JIT
    Figura 3. Attività del daemon JIT.

Il servizio Google Play è un esempio utilizzato da altre applicazioni che si comportano in modo simile alle librerie condivise.

Flusso di lavoro JIT

Architettura JIT
Figura 4. Flusso di dati JIT.
  • Le informazioni di profilazione vengono memorizzate nella cache del codice e sono soggette alla garbage collection in caso di pressione sulla memoria.
    • Non è garantito che uno snapshot acquisito quando l'applicazione era in background contenga dati completi (ovvero tutto ciò che è stato JIT).
    • Non viene effettuato alcun tentativo per garantire la registrazione di tutto (in quanto ciò può influire sulle prestazioni di runtime).
  • I metodi possono trovarsi in tre stati diversi:
    • interpretato (codice DEX)
    • Compilato JIT
    • AOT compilato
    Se esistono sia il codice JIT che AOT (ad es. a causa di ripetute de-ottimizzazioni), viene preferito il codice JIT.
  • Il requisito di memoria per eseguire JIT senza influire sulle prestazioni dell'app in primo piano dipende dall'app in questione. Le app di grandi dimensioni richiedono più memoria rispetto a quelle di piccole dimensioni. In generale, le app di grandi dimensioni si stabilizzano intorno ai 4 MB.

Attivare la registrazione JIT

Per attivare la registrazione JIT, esegui i seguenti comandi:

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

Disattiva JIT

Per disattivare JIT, esegui i seguenti comandi:

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

Forza compilazione

Per forzare la compilazione, esegui questo comando:

adb shell cmd package compile

Casi d'uso comuni per la compilazione forzata di un pacchetto specifico:

  • Basato sul profilo:
    adb shell cmd package compile -m speed-profile -f my-package
    
  • Completa:
    adb shell cmd package compile -m speed -f my-package
    

Casi d'uso comuni per la compilazione forzata di tutti i pacchetti:

  • Basato sul profilo:
    adb shell cmd package compile -m speed-profile -f -a
    
  • Completa:
    adb shell cmd package compile -m speed -f -a
    

Cancella i dati del profilo

Su Android 13 o versioni precedenti

Per cancellare i dati del profilo locale e rimuovere il codice compilato, esegui questo comando:

adb shell pm compile --reset 

Su Android 14 o versioni successive

Per cancellare solo i dati del profilo locale:

adb shell pm art clear-app-profiles 

Nota: a differenza del comando per Android 13 o versioni precedenti, questo comando non cancella i dati del profilo esterno (`.dm`) installati con l'app.

Per cancellare i dati del profilo locale e rimuovere il codice compilato generato dai dati del profilo locale (ovvero per ripristinare lo stato di installazione), esegui il comando seguente:

adb shell pm compile --reset 

Nota: questo comando non rimuove il codice compilato generato da dati del profilo esterni (`.dm`) installati con l'app.

Per cancellare tutto il codice compilato, esegui questo comando:

adb shell cmd package compile -m verify -f 

Nota: questo comando conserva i dati del profilo locale.