Android Runtime (ART) è l’ambiente di esecuzione delle applicazioni Android, introdotto in Android 5.0 Lollipop come sostituto di Dalvik. La principale innovazione è la compilazione AOT (ahead-of-time) del bytecode DEX in codice macchina nativo direttamente durante l’installazione dell’applicazione, eliminando il problema di lunga data del riscaldamento del compilatore JIT. Secondo Google, 2024, ART offre un aumento delle prestazioni dal 20–30% rispetto a Dalvik mantenendo la piena compatibilità all’indietro con il formato DEX.
Punti chiave
Android Runtime (ART) è un ambiente di esecuzione di applicazioni che compila il bytecode DEX in codice macchina nativo prima dell’esecuzione. A differenza di Dalvik, che utilizzava la compilazione Just-In-Time durante l’esecuzione, ART esegue la compilazione Ahead-Of-Time (AOT) durante l’installazione dell’APK. Questo cambiamento architetturale fondamentale ha portato a un’accelerazione significativa delle applicazioni e a un consumo energetico ridotto.
ART è apparso per la prima volta come opzione sperimentale in Android 4.4 KitKat. Gli sviluppatori potevano attivarla nelle impostazioni sviluppatore e testare le loro applicazioni. In Android 5.0 Lollipop, ART è diventato l’ambiente di esecuzione predefinito e Dalvik è stato completamente rimosso dalla piattaforma. Al momento del rilascio di Android 7.0 Nougat, ART aveva ricevuto una modalità di compilazione ibrida.
La decisione di sostituire Dalvik con ART non è stata improvvisa. Il lavoro sul nuovo ambiente è iniziato nel 2012 quando Google ha riconosciuto i limiti dell’approccio JIT. Obiettivi principali: accelerare l’avvio delle app, ridurre il carico della CPU e diminuire il consumo energetico. Lo sviluppo è stato guidato dal Android Runtime Group, che in precedenza lavorava alle ottimizzazioni di Dalvik.
ART utilizza la stessa architettura basata su registri di Dalvik, ma con un compilatore completamente riprogettato. Invece di un interprete e un compilatore JIT, ART include il compilatore AOT dex2oat, che converte i file DEX in binari ELF durante l’installazione. Di conseguenza, le applicazioni su ART si avviano immediatamente con prestazioni native, senza fase di riscaldamento.
ART ha mantenuto i principi chiave di Dalvik: isolamento delle applicazioni tramite processi separati, architettura basata su registri e supporto del formato DEX. Tuttavia, l’implementazione interna è stata completamente riscritta. Invece dell’interprete Dalvik, ART include tre modalità di esecuzione: interprete, compilatore JIT e compilatore AOT dex2oat. La selezione della modalità dipende dalla fase del ciclo di vita dell’applicazione.
Il componente chiave di ART è dex2oat (dalvik executable to optimized android translator). Questa utilità viene eseguita durante l’installazione dell’applicazione (da Android 7.0 — anche durante l’ottimizzazione in background). dex2oat legge i file DEX dall’APK, ottimizza il bytecode e genera un file OAT — un binario ELF con codice nativo. I file OAT sono memorizzati nella directory /data/dalvik-cache/.
# Verificare i file OAT sul dispositivo
adb shell ls -la /data/dalvik-cache/arm64/
# Ricompilazione forzata dell’applicazione
adb shell cmd package compile -m speed com.example.app
Il sistema ART è composto da diversi moduli interconnessi. Il compilatore dex2oat è responsabile della generazione di codice nativo. Il garbage collector (GC) gestisce la deallocazione della memoria. L’interprete esegue il codice chiamato raramente senza compilazione. Il profiler tiene traccia dei metodi caldi per la compilazione ibrida. Ogni modulo può funzionare indipendentemente, rendendo ART flessibile e scalabile.
A partire da Android 7.0 Nougat, ART utilizza un approccio ibrido alla compilazione, combinando i vantaggi di JIT e AOT. Durante l’installazione dell’applicazione, ART non esegue più la compilazione AOT completa — invece, l’app viene eseguita in modalità interpretata con compilazione JIT dei metodi caldi. Ciò riduce i tempi di installazione e lo spazio di archiviazione.
Un profiler in background lavora in parallelo. Raccoglie statistiche di esecuzione: quali metodi vengono chiamati più frequentemente, quali rami di codice vengono eseguiti, quali classi vengono caricate. Dopo aver accumulato dati sufficienti (di solito dopo 2–3 avvii dell’app), ART esegue dex2oat in background e compila solo i metodi caldi profilati in codice nativo.
ART supporta diverse modalità di compilazione, gestite tramite system_server. La modalità “speed” compila tutti i metodi con AOT (prestazioni massime, installazione lenta). La modalità “speed-profile” compila solo i metodi caldi profilati (equilibrio tra velocità e dimensione). La modalità “verify” verifica solo il bytecode senza compilazione (spazio minimo, interpretazione). Per impostazione predefinita, viene utilizzato speed-profile — ottimale per la maggior parte delle applicazioni.
| Modalità | Compilazione | Tempo di installazione | Prestazioni |
|---|---|---|---|
| speed | AOT completa | Lento | Massime |
| speed-profile | AOT profilata | Veloce | Alte |
| verify | Nessuna compilazione | Istantaneo | Interpretazione |
| space | AOT minima | Medio | Medie |
Il profiler raccoglie i dati di esecuzione in file .prof speciali. Ogni applicazione memorizza il proprio profilo in /data/misc/profiles/. Quando viene raggiunta la soglia (di solito 1000 campioni), il profiler avvia dex2oat per compilare i metodi caldi identificati. I profili vengono conservati tra gli aggiornamenti dell’applicazione, accelerando la riottimizzazione dopo gli aggiornamenti OTA del sistema.
La garbage collection in ART è notevolmente migliorata rispetto a Dalvik. Invece del Concurrent Mark and Sweep (CMS) a thread singolo, ART utilizza un collector generazionale con diverse ottimizzazioni: moving collector (compattazione dell’heap), large object space (archiviazione separata per oggetti grandi) e concurrent compaction (compattazione parallela).
Una pausa GC tipica in ART è di 2–3 ms contro 5–10 ms in Dalvik. Ciò è stato reso possibile da diversi meccanismi. Primo, ART utilizza read-barrier invece di stop-the-world per le fasi concorrenti. Secondo, il collector generazionale elabora solo la generazione giovane degli oggetti nella maggior parte dei cicli, senza toccare l’intero heap. Terzo, il large object space (LOS) viene allocato separatamente e non partecipa ai cicli GC regolari.
// Abilitare i log GC per il debug
System.logV("ART", "GC trigger: allocation failed");
// Chiamata GC forzata (non raccomandata in produzione)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Debug.getRuntimeIStats();
}
Nonostante il GC migliorato, le perdite di memoria rimangono un problema rilevante. Una causa specifica di ART è il caricamento di librerie native tramite JNI senza una corretta deallocazione. Se il codice nativo alloca memoria tramite malloc ma non chiama free, ART non può liberare questa memoria — si trova al di fuori dell’heap gestito. Lo strumento AddressSanitizer in Android NDK aiuta a identificare tali perdite.
ART e Dalvik sono due implementazioni fondamentalmente diverse dello stesso compito: eseguire applicazioni Android. Le differenze riguardano tutti i livelli: dalla compilazione alla gestione della memoria. Di seguito è riportato un confronto dei principali parametri di prestazioni e compatibilità.
Il principale vantaggio di ART è l’eliminazione del riscaldamento JIT. Su Dalvik, un’app poteva rallentare nei primi 3–10 secondi mentre JIT compilava i metodi caldi. Su ART, tutti i metodi sono già compilati in codice nativo (o verranno compilati in background). Ciò è particolarmente evidente nei giochi e nelle app con interfaccia pesante: la differenza di fps può raggiungere il 15–20% a favore di ART.
| Parametro | Dalvik | ART |
|---|---|---|
| Compilazione | JIT (durante l’esecuzione) | AOT + ibrida (all’installazione) |
| Tempo di avvio | 3–10 s (riscaldamento) | Istantaneo |
| Dimensione APK | ~6–7 MB (DEX) | +20% (OAT) |
| Pause GC | 5–10 ms | 2–3 ms |
| Consumo energetico | Più alto (JIT riscalda la CPU) | Più basso (codice nativo) |
Tutte le applicazioni scritte per Dalvik funzionano su ART senza modifiche. Google garantisce la piena compatibilità all’indietro a livello di bytecode DEX. L’eccezione è il codice che utilizza API interne specifiche di Dalvik tramite riflessione: membri della classe dalvik.system.DexFile contrassegnati con @hide in Android SDK. Tale codice deve essere aggiornato per utilizzare API pubbliche.
ART è diventato il primo ambiente di esecuzione Android con supporto nativo alle funzionalità Java 8. A partire da Android 7.0, ART include il desugaring — il processo di conversione dei costrutti Java 8 (lambda, method references, Stream API) in codice Java 7 equivalente. Ciò consente di utilizzare la sintassi moderna senza perdere la compatibilità con i dispositivi meno recenti.
Il desugaring viene eseguito dal compilatore D8 e funziona come segue. Il codice sorgente con un lambda viene convertito in un metodo sintetico all’interno della stessa classe e il lambda viene sostituito con una chiamata invoke-custom. Il runtime di ART include il supporto per l’istruzione invoke-custom, aggiunta specificamente per Java 8. Sui dispositivi con Android 6.0 e inferiore, i lambda vengono desugarizzati in classi anonime.
// Lambda Java 8 — desugaring in ART
button.setOnClickListener(v -> handleClick(v));
// Dopo il desugaring (equivalente in Java 7)
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
handleClick(v);
}
});
Non tutte le funzionalità Java 8 sono supportate dal desugaring. L’API java.time (date e ora) è disponibile solo tramite desugar_jdk_libs — una libreria aggiuntiva aggiunta in build.gradle. Stream API richiede anch’essa desugar_jdk_libs. java.util.function e Optional funzionano senza dipendenze aggiuntive. Il supporto completo di Java 8 è disponibile su dispositivi con Android 8.0 e superiore senza desugaring.
Sebbene ART sia retrocompatibile, alcune pratiche di ottimizzazione migliorano le prestazioni specificamente su questo ambiente. La raccomandazione principale è ridurre al minimo la riflessione. ART compila i metodi visibili al momento della compilazione in chiamate dirette di codice macchina. La riflessione costringe ART a generare stub aggiuntivi, rallentando l’esecuzione del 10–15%.
A partire da Android 9.0, ART ha introdotto il supporto per App Startup Optimization. Lo sviluppatore può contrassegnare le classi di inizializzazione nel manifest tramite <initialization> e ART le precaricherà all’avvio dell’app. Ciò riduce il tempo di avvio del 5–15% per le applicazioni con molti plugin o librerie.
<!-- App Startup Optimization in AndroidManifest.xml -->
<application>
<profileable
android:shell="true"
android:enable="true" />
</application>
Per misurare le prestazioni su ART, utilizzare systrace e perfetto. Systrace mostra il tempo di compilazione di dex2oat, la frequenza del GC e la velocità di rendering dei fotogrammi. Perfetto fornisce informazioni più dettagliate: distribuzione dei thread, tempo delle transizioni JNI, caricamento delle librerie native. Avvio: adb shell perfetto -o /data/misc/perfetto-traces/trace.perfetto -t 10s sched freq idle am wm.
Domande frequenti
ART (Android Runtime) è l’ambiente di esecuzione delle applicazioni Android che compila il codice dell’app in codice macchina durante l’installazione. Questo accelera l’avvio e il funzionamento delle app rispetto al vecchio ambiente Dalvik.
ART compila il codice in anticipo (AOT) durante l’installazione dell’applicazione, mentre Dalvik lo compilava pezzo per pezzo durante l’esecuzione (JIT). Pertanto, su ART, le applicazioni si avviano più velocemente e consumano meno energia.
Eseguire adb shell getprop e cercare la proprietà persist.sys.dalvik.vm.lib.2. Il valore “libart.so” significa ART, “libdvm.so” significa Dalvik. Tutti i dispositivi con Android 5.0+ utilizzano ART come ambiente di esecuzione.
Minimamente. L’applicazione stessa rimane in formato APK con file DEX. ART crea un file OAT aggiuntivo in /data/dalvik-cache/, che occupa dal 10–20% in più rispetto al DEX originale, ma questa archiviazione non è inclusa nella dimensione dell’APK.
Sì, ART supporta la maggior parte delle funzionalità Java 8 attraverso il meccanismo di desugaring. Lambda, method references e interfacce funzionali funzionano su tutti i dispositivi con Android 5.0+. Stream API e java.time richiedono la libreria desugar_jdk_libs.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche