DEX (Dalvik Executable) is het bytecodeformaat waarin de broncode van Android-applicaties in Java en Kotlin wordt gecompileerd. DEX-bestanden worden uitgevoerd door de Dalvik virtuele machine (tot Android 4.4) of Android Runtime (ART, vanaf Android 5.0). Volgens gegevens van Android Open Source Project, 2026 biedt het DEX-formaat gemiddeld 30% compactere codeweergave in vergelijking met standaard JVM-bytecode.
Belangrijkste punten
DEX (Dalvik Executable) is een bytecodeformaat dat speciaal is ontworpen voor Android-mobiele apparaten. In tegenstelling tot standaard Java-bytecode (.class-bestanden) is DEX geoptimaliseerd voor beperkte bronnen: minder geheugen, kleinere omvang en snellere klassen laden.
Broncode in Java of Kotlin wordt door javac/kotlinc gecompileerd naar standaard .class-bestanden (Java-bytecode). Vervolgens converteert de tool d8 (of eerder dx) de .class-bestanden naar een of meerdere DEX-bestanden. Deze conversie is niet simpelweg herverpakken — d8 voert optimalisaties uit: het voegt constante pools samen, herschrijft instructies naar registerarchitectuur en verwijdert dubbele gegevens.
DEX gebruikt een registerarchitectuur (in tegenstelling tot de stackgebaseerde JVM). Elke methode heeft een vast aantal registers (tot 65536). DEX-instructies zijn korter — gemiddeld 2 bytes tegenover 1–4 bytes in JVM. Dit levert compactere code op: een typische applicatie krimpt van 10–15 MB .class naar 4–6 MB .dex.
Een DEX-bestand heeft een strikt gedefinieerde binaire structuur. Elk bestand begint met een header en bevat verschillende secties die naar elkaar verwijzen via offsets.
| Sectie | Doel |
|---|---|
| header | Header: magic, controlesom, handtekening, groottes en offsets van secties |
| string_ids | Tabel met strings: namen van klassen, methoden, velden |
| type_ids | Types: verwijzingen naar stringidentificaties van types |
| proto_ids | Methodeprototypes: retourtype en parameters |
| field_ids | Klassenvelden: klasse, type, naam |
| method_ids | Methoden: klasse, prototype, naam |
| class_defs | Klassedefinities: vlaggen, superclass, interfaces, gegevensoffsets |
| data | Werkelijke gegevens: methodencode, annotaties, debug-info |
Het magische getal van DEX — `dex\n035\0` (versie 035). Andere versies: 036, 037, 038 (voor Android 8.0+). De header van 0x70 bytes bevat een SHA-1-controlesom en offsets van alle secties. Validatie van de header is de eerste stap bij het laden van DEX door de virtuele machine.
string_ids, type_ids, proto_ids, field_ids, method_ids — zijn geïndexeerde tabellen. In plaats van volledige namen in de methodencode op te slaan, wordt een 4-byte index gebruikt. Dit is de belangrijkste optimalisatie: als een klasse 100 keer wordt genoemd, wordt de naam één keer opgeslagen in string_ids. dex2oat optimaliseert deze tabellen verder tijdens ART-compilatie.
Het proces van het omzetten van broncode naar DEX bestaat uit verschillende fasen. De moderne keten gebruikt de D8-compiler, die in 2018 met Android Gradle Plugin 3.2 DX verving.
javac (voor Java) of kotlinc (voor Kotlin) compileren broncode naar .class-bestanden. Elke klasse is een apart .class-bestand in Java-bytecode. In deze fase worden typecontrole, generatie van bridge-methoden en inlining van constanten uitgevoerd.
D8 neemt alle .class-bestanden en zet ze om in DEX-bytecode. D8 voert verschillende optimalisaties uit: verwijdert ongebruikte methode-argumenten, voegt constante pools uit verschillende .class-bestanden samen in één globale DEX-pool, converteert JVM-stackinstructies naar Dalvik-registerinstructies.
// Kotlin-broncode
data class User(
val name: String,
val email: String
)
fun greet(user: User): String {
return "Hello, ${user.name}!"
}
Na D8-compilatie wordt deze code omgezet in compacte DEX-instructies: const-string voor het laden van een string, iget-object voor toegang tot een objectveld, invoke-virtual voor het aanroepen van StringBuilder.append.
D8 werkt 2–3 keer sneller dan DX, genereert compactere DEX (5–10%) en optimaliseert Kotlin-specifieke constructies (inline functies, lambda) beter. DX is sinds 2018 als deprecated gemarkeerd en verwijderd uit Android Gradle Plugin 8.0.
De uitvoering van DEX-code in Android heeft twee fasen doorlopen: de originele Dalvik virtuele machine (Android 2.2–4.4) en Android Runtime ART (Android 5.0+). Het verschil in benadering van compilatie is fundamenteel.
Dalvik gebruikte Just-In-Time (JIT) compilatie: DEX-bytecode werd geïnterpreteerd en veelgebruikte methoden werden ter plekke naar native code gecompileerd. Voordeel — snelle installatie. Nadeel — tragere opstart en constante CPU-belasting voor JIT.
ART (Android Runtime) compileert DEX bij installatie van de app via dex2oat naar native code. Dit is een Ahead-Of-Time (AOT) benadering: installatie duurt langer, maar opstarten is sneller en energieverbruik lager. Sinds Android 7.0 gebruikt ART een hybride benadering — AOT + JIT + Profile Guided Optimization.
De tool dex2oat wordt uitgevoerd bij installatie of update van een app. Het compileert DEX naar een ELF-bestand met native code voor de apparaatarchitectuur. Resultaat — .oat- en .art-bestanden in de map /data/dalvik-cache/. Google verbetert dex2oat continu: op Android 14 is optimalisatie voor opvouwbare apparaten toegevoegd.
De beperking van 65536 methoden per DEX-bestand is een erfenis van de Dalvik-architectuur. Het veld method_ids in de DEX-header beslaat 4 bytes, wat maximaal 2^16 = 65536 unieke verwijzingen geeft. Moderne apps met Google Play Services, Firebase en andere SDK's overschrijden deze limiet gemakkelijk.
Multidex is een mechanisme om code te verdelen over meerdere DEX-bestanden. Het hoofdbestand classes.dex bevat de ingangspunten (Application-klasse, hoofd-Activity), de rest — classes2.dex, classes3.dex enzovoort. Bij het opstarten worden klassen uit extra DEX-bestanden geladen via DexClassLoader.
// build.gradle.kts — multidex inschakelen
android {
defaultConfig {
multiDexEnabled = true
}
}
// Application-klasse met multidex-ondersteuning
class MyApp : Application() {
override fun attachBaseContext(base: Context) {
super.attachBaseContext(base)
MultiDex.install(this)
}
}
Het laden van extra DEX-bestanden tijdens de opstartfase kan ANR (Application Not Responding) veroorzaken op apparaten met Android tot 5.0. Aanbeveling — gebruik multidex alleen wanneer nodig en minimaliseer afhankelijkheden om de limiet niet te overschrijden.
DEX-optimalisatie is een standaard fase in het bouwen van een releaseversie van een Android-app. De tools R8 en ProGuard verkleinen de DEX, obfusceren code en verwijderen ongebruikte klassen.
R8 — de opvolger van ProGuard, geïntegreerd in Android Gradle Plugin sinds 2019. R8 voert minificatie, obfuscatie en optimalisatie uit in één pass, terwijl ProGuard twee fasen nodig had: ProGuard → D8. ProGuard wordt nog steeds ondersteund, maar Google beveelt R8 aan voor nieuwe projecten.
R8 verwijdert ongebruikte klassen, methoden en velden, hernoemt ze naar korte namen (a, b, c), inlineert functies en verwijdert dode code. Resultaat — DEX wordt 20–40% kleiner zonder functionaliteitsverlies.
De configuratie van R8 wordt ingesteld in het bestand proguard-rules.pro. De ontwikkelaar kan aangeven welke klassen niet hernoemd mogen worden (bijvoorbeeld voor reflectie of Gson-serialisatie). Firebase en andere SDK's leveren eigen regels in hun afhankelijkheden.
DEX kan terug worden gedecompileerd naar Java-code. Dit is een belangrijk beveiligingsvraagstuk voor Android-apps: zonder obfuscatie wordt code hersteld tot een niveau dat dicht bij het origineel ligt.
JADX — de meest populaire decompiler van DEX naar Java. Het herstelt klassenamen, methoden, velden en het grootste deel van de logica. apktool decompileert DEX naar smali-code (Dalvik-assembler) — een laag-niveau weergave dicht bij de oorspronkelijke instructies. Bytecode Viewer combineert meerdere decompilers in één interface.
Obfuscatie met R8/ProGuard — de eerste verdedigingslinie: klassen- en methodenamen worden onleesbaar. DexGuard — commerciële tool met extra methoden: stringversleuteling, integriteitscontrole, anti-tamper. Obfuscatie op Control Flow-niveau (O-LLVM) wijzigt de codestructuur, behoudt functionaliteit, maar maakt analyse veel moeilijker.
Veelgestelde vragen
DEX gebruikt registerarchitectuur in plaats van de stackgebaseerde JVM, heeft een compacter formaat (30% kleiner), voegt alle .class-bestanden samen in één bestand met een uniforme constante pool en gebruikt 16-bits indices in plaats van 8-bits.
Smali — is de assembler van DEX-bytecode. Elke DEX-instructie heeft een tekstuele weergave in smali-formaat. De tool baksmali converteert DEX naar smali (disassemblage), en smali assembleert smali terug naar DEX.
Gradle task countMethods of de plugin dex-method-counts tonen het aantal methoden in elk DEX-bestand. Het commando adb shell met dumpsys geeft ook statistieken van geladen DEX-bestanden voor geïnstalleerde apps.
Ja, op apparaten met Android tot 8.0 vertraagt meerdere DEX het opstarten van de app, omdat elk extra bestand afzonderlijk wordt geladen. Op ART met Android 8.0+ is het verschil minimaal dankzij compilatie door dex2oat naar één .oat-bestand.
Ja, er bestaan projecten zoals dexplorer en Android-compatibele JVM-implementaties die DEX-bytecode buiten Android kunnen uitvoeren. De meeste DEX-bestanden gebruiken echter de Android API, waardoor ze ongeschikt zijn voor uitvoering op een gewone JVM.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook