AOT — cos'è la compilazione Ahead-Of-Time e come funziona

Autore: IT Sectr Pubblicato: 2026-04-16 Tempo di lettura: 9 min

AOT (Ahead-Of-Time) — una tecnologia di compilazione in cui il codice sorgente o bytecode viene convertito in istruzioni macchina prima dell'esecuzione del programma, nella fase di build o installazione. In Android, la compilazione AOT è diventata un'innovazione chiave dell'ambiente di esecuzione ART, che ha sostituito Dalvik nella versione 5.0 Lollipop. Secondo Google, 2024, la compilazione AOT in ART elimina i ritardi di riscaldamento e riduce il consumo energetico delle applicazioni del 10–15% rispetto all'approccio JIT.

Punti chiave

  • AOT — compilazione Ahead-Of-Time: conversione del codice in codice macchina prima dell'esecuzione del programma.
  • In Android, AOT viene eseguito dall'utilità dex2oat durante l'installazione dell'APK o in background.
  • Il principale vantaggio di AOT è l'avvio istantaneo delle applicazioni senza fase di riscaldamento.
  • Lo svantaggio è un maggiore tempo di installazione e spazio su disco aggiuntivo del 15–30%.
  • I sistemi moderni utilizzano un approccio ibrido: JIT per i primi avvii, AOT per i metodi hot.

Cos'è la compilazione AOT?

Ahead-Of-Time (AOT) è un metodo di compilazione in cui un programma viene convertito in codice macchina prima di essere eseguito. Il termine “Ahead-Of-Time” contrasta con JIT (Just-In-Time): se JIT compila “appena in tempo,” allora AOT compila “in anticipo.” Un compilatore AOT prende il codice sorgente o una rappresentazione intermedia (bytecode) come input e genera un file eseguibile pronto all'uso.

La storia di AOT risale ai compilatori tradizionali di C e C++, dove la compilazione avviene sempre prima dell'esecuzione. Nel contesto dei linguaggi gestiti (Java, C#, Dart), AOT è un'innovazione più recente: per molto tempo si è creduto che le capacità dinamiche (riflessione, caricamento dinamico delle classi) rendessero AOT difficile da implementare. Google ha risolto questo problema per Android creando dex2oat — un compilatore AOT di bytecode DEX in codice nativo.

Come funziona AOT

Un compilatore AOT esegue un ciclo di traduzione completo. Il primo stadio è l'analisi sintattica e la costruzione di un albero sintattico astratto (AST). Il secondo è l'analisi e l'ottimizzazione: eliminazione di codice morto, inlining, ottimizzazione dei cicli. Il terzo è la generazione di codice macchina per l'architettura target (ARM, ARM64, x86). Il risultato è un file eseguibile che non richiede elaborazione aggiuntiva in fase di esecuzione.

bash
# Esecuzione manuale del compilatore AOT dex2oat
dex2oat --dex-file=classes.dex \
        --oat-file=classes.oat \
        --arch=arm64 \
        --instruction-set-variant=generic

# Verificare il file OAT compilato
oatdump --oat-file=classes.oat --output=oat_dump.txt

AOT in Android: dex2oat e file OAT

In Android, la compilazione AOT è implementata tramite l'utilità dex2oat (dalvik executable to optimized android translator). Quando un utente installa un'applicazione, il sistema esegue dex2oat, che legge i file DEX dall'APK, ottimizza il bytecode e crea un file OAT — un binario ELF con codice nativo. Questo file viene salvato nella partizione /data/dalvik-cache/.

Il processo di compilazione include diversi livelli di ottimizzazione. Il livello base — verifica del bytecode e ottimizzazioni di base (eliminazione di codice morto, constant folding). Il livello intermedio — inlining di metodi, srotolamento dei cicli, analisi di escape. Il livello massimo — ottimizzazioni globali dell'intera applicazione, inclusa la devirtualizzazione e l'ottimizzazione della dimensione dello stack. Il livello di ottimizzazione dipende dalla modalità di compilazione (speed, speed-profile, space).

Struttura del file OAT

Un file OAT utilizza il formato ELF (Executable and Linkable Format) — lo stesso formato utilizzato dai binari nativi Linux. All'interno del file OAT si trova il codice compilato per ogni metodo dell'applicazione, insieme ai metadati: informazioni su classi, campi, metodi e le loro relazioni. ART utilizza questi metadati per un caricamento rapido delle classi e la risoluzione dei riferimenti simbolici senza analisi completa del DEX.

Componente OATScopo
Intestazione ELFIntestazione del formato ELF
Sezione codiceCodice macchina dei metodi compilati
Intestazione OATMetadati ART: versione, dimensioni sezioni
Sezioni DEXDati DEX originali per la riflessione
Tabella di collegamentoTabella di collegamento per JNI e librerie native

AOT vs JIT: analisi comparativa

AOT e JIT rappresentano diversi punti nello spazio di compromesso tra prestazioni e flessibilità. AOT fornisce la massima velocità di esecuzione dal primo secondo, ma richiede più spazio su disco e tempo di installazione. JIT risparmia spazio e tempo di installazione, ma paga con ritardi di riscaldamento e picchi di consumo energetico.

Il fattore chiave di selezione è il caso d'uso. Per le applicazioni che vengono avviate una volta e funzionano a lungo (giochi, editor, navigazione), AOT è preferibile — i costi di compilazione sono compensati da prestazioni stabili. Per piccoli utility che vengono avviati raramente e funzionano per brevi periodi, JIT può essere più vantaggioso — installazione rapida e ingombro ridotto sono più importanti delle prestazioni di picco.

CriterioAOTJIT
AvvioIstantaneoCon riscaldamento
InstallazionePiù lenta (compilazione)Rapida
Spazio su disco+15–30%Minimo
Consumo energeticoStabilePicchi durante compilazione
AdattabilitàBassaAlta

Prestazioni del codice

Una sfumatura interessante: il codice AOT non è sempre più veloce di JIT. JIT ha accesso alle informazioni di profilazione in fase di esecuzione — tipi di oggetti precisi, frequenze di chiamata, modelli di branching reali. Ciò consente di applicare ottimizzazioni non disponibili per AOT (ad esempio, inlining guidato dal profilo). In pratica, la differenza di prestazioni del codice compilato tra AOT e JIT è di ±5–10% a seconda dello scenario.

Vantaggi della compilazione AOT

AOT fornisce tre vantaggi chiave per le applicazioni mobili. Primo — prestazioni prevedibili. L'utente non vede “balbettii” nei primi secondi: l'applicazione funziona alla massima velocità dal primo fotogramma. Questo è fondamentale per giochi, animazioni e interfacce con transizioni fluide.

Secondo — efficienza energetica. AOT non crea picchi di carico CPU tipici della compilazione JIT. Il processore opera in modalità stabile, riducendo il consumo energetico del 10–15% durante i primi 30–60 secondi di utilizzo dell'applicazione. Per un utente tipico che avvia 20–30 app al giorno, ciò offre un notevole aumento della durata della batteria.

Semplificazione del runtime

La compilazione AOT semplifica l'ambiente di esecuzione. Quando tutto il codice è già compilato, non c'è bisogno di un compilatore JIT, interprete o profiler in fase di esecuzione. Ciò riduce la dimensione del runtime stesso e diminuisce la probabilità di errori. ART in modalità AOT completa utilizza circa il 15% in meno di RAM rispetto a un ambiente simile con JIT attivo.

Svantaggi della compilazione AOT

Lo svantaggio principale di AOT è il tempo di installazione. Sui primi dispositivi con Android 5.0, l'installazione di applicazioni di grandi dimensioni (100–200 MB) poteva richiedere 2–5 minuti a causa della compilazione AOT. Ciò creava un'esperienza utente negativa: dopo il download dell'APK, gli utenti dovevano attendere prima di aprire l'applicazione. Google ha parzialmente risolto questo problema in Android 7.0 passando a uno schema ibrido.

Il secondo svantaggio è lo spazio su disco. I file OAT sono 15–30% più grandi dei file DEX originali. Su dispositivi con 8–16 GB di memoria interna, ogni applicazione “consuma” spazio aggiuntivo sulla partizione di sistema. Per gli utenti con un gran numero di applicazioni installate (50–100), ciò può portare a spazio insufficiente per gli aggiornamenti di sistema.

Mancanza di adattabilità

Il codice AOT è fissato al momento della compilazione. Se l'applicazione utilizza diversi modelli di esecuzione in base alla versione di Android, al modello del dispositivo o alle impostazioni dell'utente, AOT non può adattarsi. Le ottimizzazioni scelte per uno scenario possono essere subottimali per un altro. JIT è più flessibile in questo senso: ricompila i metodi hot quando le condizioni di esecuzione cambiano.

AOT oltre Android: Flutter, .NET, Go

La compilazione AOT non è utilizzata solo in Android. Flutter utilizza AOT per compilare il codice Dart in codice nativo per iOS e Android. Ciò garantisce prestazioni UI a 60 fps anche su dispositivi di fascia bassa. Durante lo sviluppo, Flutter utilizza JIT (hot reload), e per le build di rilascio — AOT, combinando i vantaggi di entrambi gli approcci.

Nell'ecosistema .NET, la tecnologia ReadyToRun (R2R) consente di compilare gli assembly in codice nativo in anticipo. Ciò riduce il tempo di avvio delle applicazioni .NET del 30–50%. Il compilatore Go è intrinsecamente un compilatore AOT: i programmi Go vengono compilati in un unico binario statico senza dipendenze esterne, rendendoli ideali per ambienti containerizzati.

dart
// Flutter: compilazione AOT di Dart in codice nativo
// La build di rilascio utilizza AOT
flutter build apk --release

// Risultato: libapp.so con codice Dart compilato AOT
// Lo sviluppo utilizza JIT (hot reload)
flutter run

AOT e sicurezza

Un ulteriore vantaggio di AOT è rendere più difficile il reverse engineering. Il codice nativo compilato è più difficile da decompilare rispetto al bytecode. Strumenti come JADX e APKTool funzionano con il formato DEX ma non possono recuperare il codice sorgente dai file OAT con lo stesso livello di dettaglio. Ciò non sostituisce l'offuscamento (ProGuard, R8), ma crea una barriera aggiuntiva per gli analizzatori.

Strategia ibrida: compilazione profilata

Lo standard moderno in Android è la compilazione AOT profilata, implementata in ART a partire da Android 7.0. Durante l'installazione, l'applicazione non viene completamente compilata — invece, vengono utilizzati la verifica rapida del bytecode e JIT per i primi avvii. Ciò risolve il problema della lunga installazione caratteristico dell'AOT puro in Android 5.0–6.0.

Dopo 2–3 avvii dell'applicazione, il profiler ART raccoglie dati sull'uso reale e determina quali metodi sono più critici per le prestazioni. Quindi, in background (di solito di notte quando il dispositivo è in carica), dex2oat compila questi metodi hot in codice nativo. Dopo la compilazione in background, l'applicazione raggiunge prestazioni equivalenti all'AOT completo, senza influire negativamente sull'esperienza utente durante l'installazione.

kotlin
// Controllo programmatico della modalità di compilazione (Android 9+)
fun requestProfileCompilation(context: Context) {
    val pm = context.packageManager
    // Si consiglia di utilizzare la compilazione profilata
    pm.setComponentEnabledSetting(
        ComponentName(context, javaClass()),
        PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
        PackageManager.DONT_KILL_APP
    )
}

Ottimizzazione per la modalità ibrida

Per massimizzare i vantaggi della compilazione ibrida, gli sviluppatori dovrebbero seguire alcune regole. Utilizzare profili di base (baseline profiles) — profili pre-raccolti che vengono forniti con l'APK e consentono ad ART di iniziare la compilazione AOT dei metodi hot immediatamente dopo l'installazione. I profili di base riducono il tempo per raggiungere le prestazioni complete da 2–3 avvii al primo avvio.

Domande frequenti

Cos'è la compilazione AOT in parole semplici?

AOT significa convertire un programma in codice macchina in anticipo, prima che l'utente lo esegua. Immagina che un libro sia tradotto completamente nella tua lingua prima di aprirlo — lo leggi immediatamente, senza ritardi per la traduzione delle pagine.

In cosa AOT differisce da JIT?

AOT compila il codice durante l'installazione (installazione più lenta, ma avvio più veloce). JIT compila il codice in fase di esecuzione (installazione rapida, ma i primi secondi sono più lenti). I sistemi moderni combinano entrambi gli approcci.

Perché Android è passato da Dalvik ad ART con AOT?

Google voleva eliminare il problema del riscaldamento JIT — i ritardi nei primi secondi di esecuzione dell'applicazione. La compilazione AOT in ART ha fornito un avvio istantaneo e ha ridotto il consumo energetico, che era fondamentale per i dispositivi mobili.

In che modo AOT influisce sulla dimensione dell'applicazione?

La dimensione dell'APK non cambia — la compilazione AOT crea file OAT sulla partizione di sistema che sono 15–30% più grandi dei file DEX originali. L'utente percepisce questo come una riduzione dello spazio libero di archiviazione interna, non come un aumento della dimensione del file scaricato.

Cos'è AOT profilato?

È un approccio ibrido in cui i primi avvii dell'applicazione utilizzano JIT, e poi il sistema compila in background solo i metodi utilizzati frequentemente in codice nativo. Ciò combina l'installazione rapida di JIT con le alte prestazioni di AOT.

Riepilogo

  • AOT (Ahead-Of-Time) — compilazione del bytecode in codice macchina prima dell'esecuzione del programma, nella fase di installazione.
  • In Android, AOT è implementato tramite l'utilità dex2oat, creando binari ELF (file OAT).
  • Principali vantaggi di AOT: avvio istantaneo, prestazioni stabili e basso consumo energetico.
  • Principali svantaggi: maggiore tempo di installazione e spazio su disco aggiuntivo del 15–30%.
  • AOT è utilizzato non solo in Android, ma anche in Flutter (Dart), .NET (R2R) e Go.
  • L'ART moderno utilizza AOT profilato: JIT per i primi avvii, compilazione in background dei metodi hot.
  • I profili di base consentono di iniziare la compilazione AOT dei metodi chiave immediatamente dopo l'installazione dell'applicazione.

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.

Discuti il progetto

Leggi anche