AOT (Ahead-Of-Time) — compilatietechnologie waarbij broncode of bytecode voor het starten van het programma wordt omgezet in machine-instructies, in de bouw- of installatiefase. In Android werd AOT-compilatie de belangrijkste innovatie van de ART-uitvoeringsomgeving, die Dalvik verving in versie 5.0 Lollipop. Volgens gegevens van Google, 2024 elimineert AOT-compilatie in ART opwarmvertragingen en vermindert het energieverbruik van apps met 10–15% in vergelijking met de JIT-benadering.
Belangrijkste punten
Ahead-Of-Time (AOT) — een compilatiemethode waarbij het programma vóór het starten wordt omgezet in machinecode. De term „Ahead-Of-Time" staat tegenover JIT (Just-In-Time): als JIT „op het juiste moment" compileert, dan compileert AOT — „vooraf". De AOT-compiler ontvangt broncode of een tussenliggende representatie (bytecode) en genereert een uitvoerbaar bestand dat klaar is om te draaien.
De geschiedenis van AOT gaat terug naar traditionele C- en C++-compilers, waarbij compilatie altijd vóór het uitvoeren plaatsvindt. In de context van managed talen (Java, C#, Dart) is AOT een nieuwere innovatie: lange tijd werd gedacht dat dynamische mogelijkheden (reflectie, dynamisch laden van klassen) AOT moeilijk te implementeren maken. Google loste deze taak voor Android op door dex2oat te creëren — een AOT-compiler van DEX-bytecode naar native code.
De AOT-compiler voert een volledige vertaalcyclus uit. De eerste fase — parsen en bouwen van een abstracte syntaxisboom (AST). De tweede — analyse en optimalisatie: dode code verwijderen, inlining, lusoptimalisatie. De derde — het genereren van machinecode voor de doelarchitectuur (ARM, ARM64, x86). Het resultaat is een uitvoerbaar bestand dat geen verdere verwerking tijdens het uitvoeren vereist.
# Handmatig starten van de AOT-compiler dex2oat
dex2oat --dex-file=classes.dex \
--oat-file=classes.oat \
--arch=arm64 \
--instruction-set-variant=generic
# Controleren van het gecompileerde OAT-bestand
oatdump --oat-file=classes.oat --output=oat_dump.txt
In Android wordt AOT-compilatie geïmplementeerd via het hulpprogramma dex2oat (dalvik executable to optimized android translator). Wanneer een gebruiker een app installeert, start het systeem dex2oat, dat DEX-bestanden uit het APK leest, bytecode optimaliseert en een OAT-bestand maakt — een ELF-binair bestand met native code. Dit bestand wordt opgeslagen in de partitie /data/dalvik-cache/.
Het compilatieproces omvat meerdere niveaus van optimalisatie. Het basisniveau — bytecode-verificatie en basisoptimalisaties (dead code elimination, constant folding). Het gemiddelde — methoden inlining, loop unrolling, escape-analyse. Het maximale — globale optimalisaties van de hele app, inclusief devirtualisatie en optimalisatie van de stackgrootte. Het optimalisatieniveau hangt af van de compilatiemodus (speed, speed-profile, space).
Het OAT-bestand heeft het ELF-formaat (Executable and Linkable Format) — hetzelfde formaat dat native Linux-binary's gebruiken. In het OAT-bestand bevindt zich gecompileerde code voor elke methode van de app, evenals metadata: informatie over klassen, velden, methoden en relaties ertussen. ART gebruikt deze metadata voor snel laden van klassen en het oplossen van symbolische verwijzingen zonder volledig parsen van DEX.
| OAT-component | Doel |
|---|---|
| ELF header | Koptekst van het ELF-formaat |
| Code section | Machinecode van gecompileerde methoden |
| OAT header | ART-metadata: versie, sectiegroottes |
| DEX sections | Originele DEX-gegevens voor reflectie |
| Link table | Verbindingstabel voor JNI en native bibliotheken |
AOT en JIT vertegenwoordigen verschillende punten in de ruimte van compromissen tussen prestaties en flexibiliteit. AOT biedt maximale uitvoeringssnelheid vanaf de eerste seconde, maar vereist meer schijfruimte en installatietijd. JIT bespaart ruimte en installatietijd, maar betaalt daarvoor met opwarmvertraging en piekenergieverbruik.
De belangrijkste factor bij de keuze — het gebruiksscenario. Voor apps die één keer worden gestart en lang draaien (games, editors, navigatie) heeft AOT de voorkeur — de compilatiekosten worden terugverdiend door stabiele prestaties. Voor kleine hulpprogramma's die zelden en kort worden gestart, kan JIT voordeliger zijn — snelle installatie en weinig ruimte zijn belangrijker dan piekprestaties.
| Criterium | AOT | JIT |
|---|---|---|
| Opstarten | Direct | Met opwarmen |
| Installatie | Langer (compilatie) | Snel |
| Schijfruimte | +15–30% | Minimaal |
| Energieverbruik | Stabiel | Pieken bij compilatie |
| Aanpasbaarheid | Laag | Hoog |
Een interessante nuance: AOT-code is niet altijd sneller dan JIT. JIT heeft toegang tot profielinformatie van de uitvoeringstijd — exacte objecttypen, aanroepfrequenties, echte vertakkingspatronen. Dit maakt optimalisaties mogelijk die niet beschikbaar zijn voor AOT (bijvoorbeeld profielgestuurd inlinen). In de praktijk bedraagt het verschil in prestaties van gecompileerde code tussen AOT en JIT ±5–10%, afhankelijk van het scenario.
AOT biedt drie belangrijke voordelen voor mobiele apps. Ten eerste — voorspelbare prestaties. De gebruiker ziet geen 'haperingen' in de eerste seconden van gebruik: de app werkt op maximale snelheid vanaf het eerste frame. Dit is cruciaal voor games, animaties en interfaces met vloeiende overgangen.
Ten tweede — energie-efficiëntie. AOT creëert geen piekbelastingen van de CPU die kenmerkend zijn voor JIT-compilatie. De processor werkt in een stabiele modus, wat het energieverbruik met 10–15% vermindert in de eerste 30–60 seconden van de app. Voor een typische gebruiker die 20–30 apps per dag start, levert dit een merkbare toename van de batterijduur op.
AOT-compilatie vereenvoudigt de runtime-omgeving. Wanneer alle code al is gecompileerd, is er geen behoefte meer aan een JIT-compiler, interpreter en profiler tijdens het uitvoeren. Dit verkleint de omvang van de runtime-omgeving zelf en verlaagt de kans op fouten. ART in volledige AOT-modus gebruikt ongeveer 15% minder RAM dan een vergelijkbare omgeving met actieve JIT.
Het grootste nadeel van AOT — installatietijd. Op vroege apparaten met Android 5.0 kon de installatie van grote apps (100–200 MB) 2–5 minuten duren vanwege AOT-compilatie. Dit zorgde voor een negatieve gebruikerservaring: na het downloaden van het APK moest men wachten voordat de app kon worden geopend. Google loste dit probleem gedeeltelijk op in Android 7.0 door over te stappen op een hybride schema.
Het tweede nadeel — schijfruimte. OAT-bestanden zijn 15–30% groter dan de originele DEX-bestanden. Op apparaten met 8–16 GB ingebouwd geheugen 'eet' elke app extra ruimte op de systeempartitie. Voor gebruikers met veel geïnstalleerde apps (50–100) kan dit leiden tot ruimtegebrek voor systeemupdates.
AOT-code wordt vastgelegd op het moment van compilatie. Als een app verschillende uitvoeringspatronen gebruikt afhankelijk van de Android-versie, apparaatmodel of gebruikersinstellingen, kan AOT zich niet aanpassen. Optimalisaties die voor het ene scenario zijn gekozen, kunnen suboptimaal zijn voor een ander. JIT is in dit opzicht flexibeler: het hercompileert hot-methoden wanneer de uitvoeringsomstandigheden veranderen.
AOT-compilatie wordt niet alleen in Android gebruikt. Flutter gebruikt AOT voor het compileren van Dart-code naar native code voor iOS en Android. Dit garandeert UI-prestaties op het niveau van 60 fps, zelfs op zwakkere apparaten. In de ontwikkelfase gebruikt Flutter JIT (hot reload) en voor de release-build — AOT, waarbij de voordelen van beide benaderingen worden gecombineerd.
In het .NET-ecosysteem maakt de technologie ReadyToRun (R2R) het mogelijk om assemblies vooraf naar native code te compileren. Dit verkort de opstarttijd van .NET-apps met 30–50%. De Go-compiler is van nature een AOT-compiler: Go-programma's worden gecompileerd naar één statische binary zonder externe afhankelijkheden, wat ze ideaal maakt voor containeromgevingen.
// Flutter: AOT-compilatie van Dart-code naar native code
// Release-build gebruikt AOT
flutter build apk --release
// Resultaat: libapp.so met AOT-gecompileerde Dart-code
// Ontwikkeling gebruikt JIT (hot reload)
flutter run
Een bijkomend voordeel van AOT — het bemoeilijken van reverse engineering. Gecompileerde native code is moeilijker te decompileren dan bytecode. Hulpprogramma's zoals JADX en APKTool werken met het DEX-formaat, maar kunnen de broncode niet uit OAT-bestanden herstellen op hetzelfde detailniveau. Dit vervangt obfuscatie (ProGuard, R8) niet, maar creëert een extra barrière voor analisten.
De moderne standaard in Android — geprofileerde AOT-compilatie, geïmplementeerd in ART vanaf Android 7.0. Bij installatie wordt de app niet volledig gecompileerd — in plaats daarvan wordt snelle bytecode-verificatie en JIT gebruikt voor de eerste starts. Dit lost het probleem van lange installatietijd op dat kenmerkend was voor pure AOT in Android 5.0–6.0.
Na 2–3 keer starten van de app verzamelt de ART-profiler gegevens over het feitelijke gebruik en bepaalt welke methoden het meest kritisch zijn voor de prestaties. Vervolgens compileert dex2oat op de achtergrond (meestal 's nachts wanneer het apparaat wordt opgeladen) deze hot-methoden naar native code. Na achtergrondcompilatie bereikt de app prestaties die gelijkwaardig zijn aan volledige AOT, zonder negatieve invloed op de gebruikerservaring bij installatie.
// Programmatisch beheer van compilatiemodus (Android 9+)
fun requestProfileCompilation(context: Context) {
val pm = context.packageManager
// Het wordt aanbevolen om geprofileerde compilatie te gebruiken
pm.setComponentEnabledSetting(
ComponentName(context, javaClass()),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP
)
}
Voor maximaal profijt van hybride compilatie moeten ontwikkelaars een aantal regels volgen. Gebruik basisprofielen (baseline profiles) — vooraf verzamelde profielen die samen met het APK worden geleverd en ART in staat stellen om onmiddellijk na installatie te beginnen met AOT-compilatie van hot-methoden. Baseline profiles verkorten de tijd tot het bereiken van volledige prestaties van 2–3 keer opstarten tot de eerste keer opstarten.
Veelgestelde vragen
AOT — het vertalen van een programma naar machinecode vooraf, voordat de gebruiker het start. Stel je voor dat een boek volledig in het Nederlands is verteld voordat je het opent — je leest meteen, zonder vertraging voor het vertalen van pagina's.
AOT compileert code bij installatie (langere installatie, maar snellere start). JIT compileert code tijdens het uitvoeren (snelle installatie, maar de eerste seconden is de app trager). Moderne systemen combineren beide benaderingen.
Google wilde het probleem van JIT-opwarming elimineren — vertragingen in de eerste seconden van de app. AOT-compilatie in ART zorgde voor direct opstarten en verminderde het energieverbruik, wat cruciaal was voor mobiele apparaten.
De APK-grootte verandert niet — AOT-compilatie maakt OAT-bestanden op de systeempartitie die 15–30% groter zijn dan de originele DEX. De gebruiker ziet dit als een afname van de vrije ruimte in het ingebouwde geheugen, niet als een toename van de grootte van het te downloaden bestand.
Dit is een hybride aanpak waarbij de eerste starts van de app JIT gebruiken en het systeem vervolgens op de achtergrond alleen veelgebruikte methoden naar native code compileert. Dit combineert de snelle installatie van JIT met de hoge prestaties van AOT.
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