DEX (Dalvik Executable) este formatul de bytecod în care se compilează codul sursă al aplicațiilor Android în Java și Kotlin. Fișierele DEX sunt executate de mașina virtuală Dalvik (până la Android 4.4) sau Android Runtime (ART, începând cu Android 5.0). Conform datelor Android Open Source Project, 2026, formatul DEX asigură în medie o reprezentare 30% mai compactă a codului în comparație cu bytecodul standard JVM.
Principalele puncte
DEX (Dalvik Executable) este un format de bytecod proiectat special pentru dispozitivele mobile Android. Spre deosebire de bytecodul standard Java (fișiere .class), DEX este optimizat pentru resurse limitate: mai puțină memorie, dimensiune mai mică și încărcare mai rapidă a claselor.
Codul sursă în Java sau Kotlin este compilat de javac/kotlinc în fișiere .class standard (bytecod Java). Apoi instrumentul d8 (sau anterior dx) convertește .class într-unul sau mai multe fișiere DEX. Această conversie nu este o simplă reambalare — d8 efectuează optimizări: îmbină pool-urile de constante, rescrie instrucțiunile în arhitectura pe registre și elimină datele duplicate.
DEX utilizează arhitectura pe registre (spre deosebire de arhitectura pe stivă a JVM). Fiecare metodă are un număr fix de registre (până la 65536). Instrucțiunile DEX sunt mai scurte — în medie 2 octeți față de 1–4 octeți în JVM. Acest lucru oferă un cod mai compact: o aplicație tipică se reduce de la 10–15 MB .class la 4–6 MB .dex.
Fișierul DEX are o structură binară strict definită. Fiecare fișier începe cu un antet și conține mai multe secțiuni care se referă unele la altele prin offset-uri.
| Secțiune | Scop |
|---|---|
| header | Antet: magic, sumă de control, semnătură, dimensiuni și offset-uri ale secțiunilor |
| string_ids | Tabel de șiruri: nume de clase, metode, câmpuri |
| type_ids | Tipuri: referințe la identificatorii de șiruri ale tipurilor |
| proto_ids | Prototipuri de metode: tipul returnat și parametrii |
| field_ids | Câmpuri ale claselor: clasă, tip, nume |
| method_ids | Metode: clasă, prototip, nume |
| class_defs | Definiții de clase: flag-uri, superclass, interfețe, offset-uri ale datelor |
| data | Datele efective: codul metodelor, adnotări, informații de debug |
Numărul magic DEX — `dex\n035\0` (versiunea 035). Alte versiuni: 036, 037, 038 (pentru Android 8.0+). Antetul de dimensiune 0x70 octeți conține suma de control SHA-1 și offset-urile tuturor secțiunilor. Validarea antetului — primul pas la încărcarea DEX de către mașina virtuală.
string_ids, type_ids, proto_ids, field_ids, method_ids — sunt tabele indexate. În locul stocării numelor complete în codul metodei, se utilizează un index de 4 octeți. Aceasta este optimizarea cheie: dacă o clasă este menționată de 100 de ori, numele său este stocat o singură dată în string_ids. dex2oat la compilarea ART optimizează suplimentar aceste tabele.
Procesul de transformare a codului sursă în DEX constă din mai multe etape. Lanțul modern folosește compilatorul D8, care l-a înlocuit pe DX în 2018 cu Android Gradle Plugin 3.2.
javac (pentru Java) sau kotlinc (pentru Kotlin) compilează codul sursă în fișiere .class. Fiecare clasă — un fișier .class separat în bytecod Java. În această etapă se efectuează verificarea tipurilor, generarea metodelor de punte și încorporarea constantelor.
D8 primește toate fișierele .class și le transformă în bytecod DEX. D8 efectuează mai multe optimizări: elimină argumentele neutilizate ale metodelor, îmbină pool-urile de constante din diferite .class într-un singur pool global DEX, convertește instrucțiunile pe stivă JVM în instrucțiuni pe registre Dalvik.
// Codul sursă Kotlin
data class User(
val name: String,
val email: String
)
fun greet(user: User): String {
return "Hello, ${user.name}!"
}
După compilarea D8, acest cod se transformă în instrucțiuni compacte DEX: const-string pentru încărcarea unui șir, iget-object pentru accesarea unui câmp al obiectului, invoke-virtual pentru apelarea StringBuilder.append.
D8 funcționează de 2–3 ori mai rapid decât DX, generează un DEX mai compact (cu 5–10%) și optimizează mai bine construcțiile specifice Kotlin (funcții inline, lambda). DX a fost declarat deprecated din 2018 și eliminat din Android Gradle Plugin 8.0.
Execuția codului DEX în Android a trecut prin două etape: mașina virtuală originală Dalvik (Android 2.2–4.4) și Android Runtime ART (Android 5.0+). Diferența în abordarea compilării este fundamentală.
Dalvik utiliza compilarea Just-In-Time (JIT): bytecodul DEX era interpretat, iar metodele frecvent apelate erau compilate în cod nativ pe loc. Avantaj — instalare rapidă. Dezavantaj — pornire mai lentă și consum constant de CPU pentru JIT.
ART (Android Runtime) compilează DEX în cod nativ la instalarea aplicației prin dex2oat. Aceasta este o abordare Ahead-Of-Time (AOT): instalarea durează mai mult, dar pornirea este mai rapidă și consumul de energie mai mic. Din Android 7.0 ART utilizează o abordare hibridă — AOT + JIT + Profile Guided Optimization.
Instrumentul dex2oat rulează la instalarea sau actualizarea aplicației. Acesta compilează DEX într-un fișier ELF cu cod nativ pentru arhitectura dispozitivului. Rezultatul — fișierele .oat și .art în directorul /data/dalvik-cache/. Google îmbunătățește constant dex2oat: pe Android 14 a fost adăugată optimizarea pentru dispozitivele pliabile.
Limitarea la 65536 de metode per fișier DEX — o moștenire a arhitecturii Dalvik. Câmpul method_ids din antetul DEX ocupă 4 octeți, ceea ce oferă maximum 2^16 = 65536 de referințe unice. Aplicațiile moderne cu Google Play Services, Firebase și alte SDK-uri depășesc ușor această limită.
Multidex este un mecanism de împărțire a codului în mai multe fișiere DEX. Fișierul principal classes.dex conține punctele de intrare (clasa Application, Activity-urile principale), restul — classes2.dex, classes3.dex și așa mai departe. La pornire, clasele din DEX-urile suplimentare sunt încărcate prin DexClassLoader.
// build.gradle.kts — activarea multidex
android {
defaultConfig {
multiDexEnabled = true
}
}
// Clasa Application cu suport multidex
class MyApp : Application() {
override fun attachBaseContext(base: Context) {
super.attachBaseContext(base)
MultiDex.install(this)
}
}
Încărcarea DEX-urilor suplimentare în faza de pornire a aplicației poate cauza ANR (Application Not Responding) pe dispozitivele cu Android până la 5.0. Recomandare — utilizați multidex doar la necesitate și minimizați dependențele pentru a nu depăși limita.
Optimizarea DEX — etapa standard a construirii versiunii de release a aplicației Android. Instrumentele R8 și ProGuard reduc dimensiunea DEX, ofuscă codul și elimină clasele neutilizate.
R8 — succesorul lui ProGuard, integrat în Android Gradle Plugin din 2019. R8 efectuează minificarea, ofuscarea și optimizarea într-o singură trecere, în timp ce ProGuard necesita două etape: ProGuard → D8. ProGuard este încă suportat, dar Google recomandă R8 pentru proiectele noi.
R8 elimină clasele, metodele și câmpurile neutilizate, le redenumește cu nume scurte (a, b, c), încorporează funcțiile inline și aruncă codul mort. Rezultatul — DEX se reduce cu 20–40% fără pierderea funcționalității.
Configurația R8 se definește în fișierul proguard-rules.pro. Dezvoltatorul poate specifica ce clase nu trebuie redenumite (de exemplu, pentru reflecție sau serializare Gson). Firebase și alte SDK-uri furnizează propriile reguli în dependențele lor.
DEX poate fi decompilat înapoi în cod Java. Aceasta este o problemă cheie de securitate a aplicațiilor Android: fără ofuscare, codul este restaurat la un nivel apropiat de original.
JADX — cel mai popular decompilator DEX în Java. Acesta restaurează numele claselor, metodelor, câmpurilor și cea mai mare parte a logicii. apktool decompilează DEX în cod smali (asamblor Dalvik) — o reprezentare de nivel scăzut apropiată de instrucțiunile originale. Bytecode Viewer combină mai multe decompilatoare într-o singură interfață.
Ofuscarea R8/ProGuard — prima linie de apărare: numele claselor și metodelor devin ilizibile. DexGuard — instrument comercial cu metode suplimentare: criptarea șirurilor, verificarea integrității, anti-tamper. Ofuscarea la nivel de Control Flow (O-LLVM) modifică structura codului, păstrându-i funcționalitatea, dar făcând analiza mult mai dificilă.
Întrebări frecvente
DEX utilizează arhitectura pe registre în locul celei pe stivă a JVM, are un format mai compact (cu 30% mai mic), îmbină toate fișierele .class într-un singur fișier cu un pool unic de constante și utilizează indecși pe 16 biți în loc de 8 biți.
Smali — este asamblorul bytecodului DEX. Fiecare instrucțiune DEX are o reprezentare textuală în format smali. Instrumentul baksmali convertește DEX în smali (dezasamblare), iar smali asamblează smali înapoi în DEX.
Gradle task countMethods sau pluginul dex-method-counts arată numărul de metode în fiecare fișier DEX. Comanda adb shell cu dumpsys afișează, de asemenea, statisticile DEX-urilor încărcate pentru aplicațiile instalate.
Da, pe dispozitivele cu Android până la 8.0, DEX-urile multiple încetinesc pornirea aplicației, deoarece fiecare fișier suplimentar este încărcat separat. Pe ART cu Android 8.0+ diferența este minimă datorită compilării dex2oat într-un singur fișier .oat.
Da, există proiecte precum dexplorer și implementări JVM compatibile cu Android care pot executa bytecod DEX în afara Android. Cu toate acestea, majoritatea fișierelor DEX utilizează Android API, ceea ce le face nepotrivite pentru rularea pe o JVM obișnuită.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și