DEX: cos'è, struttura e principio di funzionamento del bytecode

Autore: IT Sectr Pubblicato: 2026-04-15 Tempo di lettura: 8 min

DEX (Dalvik Executable) è un formato di bytecode in cui viene compilato il codice sorgente delle applicazioni Android in Java e Kotlin. I file DEX vengono eseguiti dalla macchina virtuale Dalvik (fino ad Android 4.4) o da Android Runtime (ART, a partire da Android 5.0). Secondo Android Open Source Project, 2026, il formato DEX fornisce in media una rappresentazione del codice 30% più compatta rispetto al bytecode Java standard della JVM.

Punti chiave

  • DEX è un formato di bytecode per Android, eseguito su Dalvik o ART.
  • Compattezza — DEX occupa il 30% in meno di spazio rispetto al bytecode Java standard.
  • Multidex — un meccanismo per aggirare il limite di 65536 metodi in un singolo file DEX.
  • ART — Android Runtime, che ha sostituito Dalvik, compila DEX in codice nativo durante l'installazione.
  • D8 — un compilatore moderno da Java/Kotlin a DEX, che ha sostituito DX dal 2018.

Cos'è DEX e perché serve

DEX (Dalvik Executable) è un formato di bytecode progettato specificamente per i dispositivi mobili Android. A differenza del bytecode Java standard (file .class), DEX è ottimizzato per risorse limitate: meno memoria, dimensioni ridotte e caricamento delle classi più veloce.

Da Java a DEX

Il codice sorgente in Java o Kotlin viene compilato da javac/kotlinc in file .class standard (bytecode Java). Successivamente, lo strumento d8 (o in precedenza dx) converte i .class in uno o più file DEX. Questa conversione non è un semplice reimpacchettamento — d8 esegue ottimizzazioni: unisce i pool di costanti, riscrive le istruzioni in architettura a registri e rimuove i dati duplicati.

Caratteristiche architetturali

DEX utilizza un'architettura basata su registri (a differenza della JVM basata su stack). Ogni metodo ha un numero fisso di registri (fino a 65536). Le istruzioni DEX sono più corte — in media 2 byte contro 1–4 byte nella JVM. Questo produce codice più compatto: un'applicazione tipica si riduce da 10–15 MB di .class a 4–6 MB di .dex.

Struttura del file DEX: sezioni e intestazione

Un file DEX ha una struttura binaria rigorosamente definita. Ogni file inizia con un'intestazione e contiene diverse sezioni che si riferiscono l'una all'altra tramite offset.

SezioneScopo
headerIntestazione: magic, checksum, firma, dimensioni e offset delle sezioni
string_idsTabella delle stringhe: nomi di classi, metodi, campi
type_idsTipi: riferimenti agli identificatori di stringa dei tipi
proto_idsPrototipi di metodi: tipo restituito e parametri
field_idsCampi delle classi: classe, tipo, nome
method_idsMetodi: classe, prototipo, nome
class_defsDefinizioni di classi: flag, superclasse, interfacce, offset dei dati
dataDati effettivi: codice dei metodi, annotazioni, informazioni di debug

Intestazione DEX

Il numero magico di DEX è `dex\n035\0` (versione 035). Altre versioni: 036, 037, 038 (per Android 8.0+). L'intestazione è di 0x70 byte e contiene un checksum SHA-1 e gli offset di tutte le sezioni. La validazione dell'intestazione è il primo passo quando la macchina virtuale carica un DEX.

Pool di costanti

string_ids, type_ids, proto_ids, field_ids, method_ids — sono tabelle indicizzate. Invece di memorizzare i nomi completi nel codice del metodo, viene utilizzato un indice di 4 byte. Questa è un'ottimizzazione chiave: se una classe viene menzionata 100 volte, il suo nome viene memorizzato una volta in string_ids. dex2oat ottimizza ulteriormente queste tabelle durante la compilazione ART.

Processo di compilazione di Java e Kotlin in DEX

Il processo di conversione del codice sorgente in DEX consiste in diverse fasi. La catena di strumenti moderna utilizza il compilatore D8, che ha sostituito DX nel 2018 con Android Gradle Plugin 3.2.

Fase 1: Compilazione in .class

javac (per Java) o kotlinc (per Kotlin) compila il codice sorgente in file .class. Ogni classe è un file .class separato in bytecode Java. In questa fase vengono eseguiti il controllo dei tipi, la generazione di metodi bridge e l'inlining delle costanti.

Fase 2: Compilazione D8

D8 prende tutti i file .class e li trasforma in bytecode DEX. D8 esegue diverse ottimizzazioni: rimuove argomenti di metodi inutilizzati, unisce i pool di costanti da diversi file .class in un unico pool DEX globale e converte le istruzioni stack JVM in istruzioni registro Dalvik.

kotlin
// Codice sorgente Kotlin
data class User(
    val name: String,
    val email: String
)

fun greet(user: User): String {
    return "Hello, ${user.name}!"
}

Dopo la compilazione D8, questo codice si trasforma in istruzioni DEX compatte: const-string per caricare stringhe, iget-object per accedere al campo di un oggetto, invoke-virtual per chiamare StringBuilder.append.

D8 vs DX

D8 è 2–3 volte più veloce di DX, genera DEX più compatto (5–10% più piccolo) e ottimizza meglio le costruzioni specifiche di Kotlin (funzioni inline, lambda). DX è stato dichiarato deprecato nel 2018 e rimosso da Android Gradle Plugin 8.0.

Dalvik vs ART: come è cambiata l'esecuzione di DEX

L'esecuzione del codice DEX in Android ha attraversato due fasi: la macchina virtuale Dalvik originale (Android 2.2–4.4) e Android Runtime ART (Android 5.0+). La differenza nell'approccio di compilazione è fondamentale.

Dalvik VM: compilazione JIT

Dalvik utilizzava la compilazione Just-In-Time (JIT): il bytecode DEX veniva interpretato e i metodi chiamati frequentemente venivano compilati in codice nativo al volo. Vantaggio — installazione rapida. Svantaggio — avvio più lento e consumo costante di CPU per JIT.

ART: compilazione AOT

ART (Android Runtime) compila DEX in codice nativo durante l'installazione dell'applicazione tramite dex2oat. Questo è un approccio Ahead-Of-Time (AOT): l'installazione è più lunga, ma l'avvio è più veloce e il consumo energetico è inferiore. Da Android 7.0, ART utilizza un approccio ibrido — AOT + JIT + ottimizzazione guidata dal profilo.

dex2oat: conversione durante l'installazione

Lo strumento dex2oat viene eseguito durante l'installazione o l'aggiornamento di un'applicazione. Compila DEX in un file ELF con codice nativo per l'architettura del dispositivo. Il risultato — file .oat e .art nella directory /data/dalvik-cache/. Google migliora continuamente dex2oat: su Android 14 sono state aggiunte ottimizzazioni per i dispositivi pieghevoli.

Multidex: superamento del limite dei 64K metodi

Il limite di 65536 metodi per file DEX è un'eredità dell'architettura Dalvik. Il campo method_ids nell'intestazione DEX occupa 4 byte, dando un massimo di 2^16 = 65536 riferimenti univoci. Le applicazioni moderne con Google Play Services, Firebase e altri SDK superano facilmente questo limite.

Meccanismo Multidex

Multidex è un meccanismo per dividere il codice in più file DEX. Il classes.dex principale contiene i punti di ingresso (classe Application, Activity principale), gli altri sono classes2.dex, classes3.dex e così via. All'avvio, le classi dai DEX aggiuntivi vengono caricate tramite DexClassLoader.

kotlin
// build.gradle.kts — abilitazione multidex
android {
    defaultConfig {
        multiDexEnabled = true
    }
}

// Classe Application con supporto multidex
class MyApp : Application() {
    override fun attachBaseContext(base: Context) {
        super.attachBaseContext(base)
        MultiDex.install(this)
    }
}

Problemi di Multidex

Il caricamento di DEX aggiuntivi durante l'avvio dell'applicazione può causare ANR (Application Not Responding) sui dispositivi con Android precedente al 5.0. Raccomandazione — utilizzare multidex solo quando necessario e minimizzare le dipendenze per non superare il limite.

Ottimizzazione DEX: ProGuard, R8 e offuscamento

L'ottimizzazione di DEX è un passaggio standard nella creazione di un'applicazione Android in versione release. Gli strumenti R8 e ProGuard riducono le dimensioni del DEX, offuscano il codice e rimuovono le classi inutilizzate.

R8 vs ProGuard

R8 è il successore di ProGuard, integrato in Android Gradle Plugin dal 2019. R8 esegue minimizzazione, offuscamento e ottimizzazione in un unico passaggio, mentre ProGuard richiedeva due fasi: ProGuard → D8. ProGuard è ancora supportato, ma Google raccomanda R8 per i nuovi progetti.

R8 rimuove classi, metodi e campi inutilizzati, li rinomina con nomi brevi (a, b, c), incorpora funzioni inline ed elimina il codice morto. Il risultato — il DEX viene ridotto del 20–40% senza perdita di funzionalità.

Regole R8

La configurazione di R8 viene specificata nel file proguard-rules.pro. Lo sviluppatore può indicare quali classi non possono essere rinominare (ad esempio, per riflessione o serializzazione Gson). Firebase e altri SDK forniscono le proprie regole nelle loro dipendenze.

Decompilazione DEX: strumenti e protezione

DEX può essere decompilato in codice Java. Questa è una questione di sicurezza fondamentale per le applicazioni Android: senza offuscamento, il codice viene ripristinato a un livello vicino all'originale.

Strumenti di decompilazione

JADX è il decompilatore da DEX a Java più popolare. Ripristina nomi di classi, metodi, campi e la maggior parte della logica. apktool decompila DEX in codice smali (assembler Dalvik) — una rappresentazione di basso livello vicina alle istruzioni originali. Bytecode Viewer combina più decompilatori in un'unica interfaccia.

Metodi di protezione

L'offuscamento con R8/ProGuard è la prima linea di difesa: i nomi di classi e metodi diventano illeggibili. DexGuard è uno strumento commerciale con metodi aggiuntivi: crittografia delle stringhe, verifica dell'integrità, anti-manomissione. L'offuscamento del flusso di controllo (O-LLVM) modifica la struttura del codice mantenendone la funzionalità, rendendo l'analisi molto più difficile.

Domande frequenti

In cosa DEX differisce dal bytecode Java?

DEX utilizza un'architettura basata su registri invece della JVM basata su stack, ha un formato più compatto (30% più piccolo), unisce tutti i .class in un unico file con un pool di costanti unificato e utilizza indici a 16 bit invece di 8 bit.

Cos'è smali?

Smali è un assembler per bytecode DEX. Ogni istruzione DEX ha una rappresentazione testuale in formato smali. Lo strumento baksmali converte DEX in smali (disassemblaggio) e smali assembla smali di nuovo in DEX.

Come verificare il numero di metodi in DEX?

Il task Gradle countMethods o il plugin dex-method-counts mostrano il numero di metodi in ogni file DEX. Il comando adb shell con dumpsys mostra anche le statistiche dei DEX caricati per le applicazioni installate.

Il numero di file DEX influisce sulle prestazioni?

, sui dispositivi con Android precedente all'8.0, più file DEX rallentano l'avvio dell'applicazione perché ogni file aggiuntivo viene caricato separatamente. Su ART con Android 8.0+, la differenza è minima grazie alla compilazione dex2oat in un singolo file .oat.

Si può eseguire DEX senza Android?

, esistono progetti come dexplorer e implementazioni JVM compatibili con Android che possono eseguire bytecode DEX al di fuori di Android. Tuttavia, la maggior parte dei file DEX utilizza l'API Android, rendendoli inadatti all'esecuzione su una JVM standard.

Riepilogo

  • DEX è un formato di bytecode Android con architettura basata su registri e rappresentazione compatta del codice.
  • Struttura include intestazione, tabelle degli identificatori e sezione dati con istruzioni.
  • Compilazione in DEX avviene tramite D8: .class → DEX con ottimizzazioni e unione dei pool di costanti.
  • ART compila DEX in codice nativo durante l'installazione (AOT), accelerando l'avvio dell'applicazione.
  • Multidex risolve il limite di 65536 metodi suddividendo in più file DEX.
  • Ottimizzazione — R8 riduce DEX del 20–40%, offusca i nomi e rimuove il codice morto.
  • Protezione — offuscamento con R8/ProGuard, DexGuard e O-LLVM impedisce la decompilazione di DEX.

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