If you've ever wondered why installing an app on Android takes a moment, or why apps feel snappier on newer devices — the answer lies in the transition from Dalvik to ART and the evolution of compilation strategies.
Dalvik (Android 1.0–4.4)
Dalvik ran .dex (Dalvik Executable) bytecode. It used Just-In-Time (JIT) compilation: methods were interpreted first, and frequently-called ("hot") methods were compiled to native code at runtime.
Problems with Dalvik JIT:
- JIT compilation happens at runtime → slower startup
- No optimization between app sessions (JIT cache was discarded)
- 32-bit only
- Higher CPU usage during JIT compilation (battery impact)
ART (Android 5.0+): AOT Compilation
Android Runtime replaced Dalvik. The initial approach: Ahead-Of-Time (AOT) compilation with dex2oat at install time.
.apk → dex2oat → .oat (ELF binary with native code)
ART AOT benefits:
- Much faster runtime execution (pre-compiled native code)
- No JIT overhead during execution
- Better GC (compacting, precise type information)
AOT drawback:
- Install time increased significantly (full AOT compilation)
.oatfiles are large (storage cost)
Android 7.0+: JIT + AOT Hybrid with Profile-Guided Optimization
Pure AOT had too high an install cost. Android 7 introduced a hybrid approach:
Install: .apk → quick dex2oat (just verify, minimal compile)
First run: JIT compiles hot methods, records which methods are hot → profile file
Background: dex2oat uses profile to AOT-compile hot paths only
Next runs: hot paths run as native AOT code; cold paths still JIT'd
This is Profile-Guided Optimization (PGO), and it gives you:
- Fast installs (no full AOT at install time)
- Near-AOT performance after the first session or two
- Storage savings (only hot paths compiled)
# See compiled method status for your app
adb shell oatdump --app-image=/data/dalvik-cache/arm64/... | head -50
# Force AOT compilation (for testing)
adb shell cmd package compile -m speed com.example.myapp
Compilation Filter Modes
dex2oat accepts a --compiler-filter argument:
| Filter | What it does | Used when |
|---|---|---|
verify | Just verify bytecode, no compilation | Install time (fast) |
quicken | Quicken interpreter opcodes | Rarely |
space | Compile, optimize for size | Storage-constrained |
speed | Full AOT compilation | System apps, forced |
speed-profile | AOT only hot methods from profile | Default for user apps after profiling |
everything | AOT everything | Testing |
R8 and D8: Your Build-Time Compilers
These run during your build, before the device ever sees your code:
- D8 (replaces dx): Converts
.classbytecode to.dex. Produces smaller, more efficient dex than dx. - R8 (replaces ProGuard + dx): Combines shrinking, obfuscation, and dex compilation in one step. Enables dead code elimination and inlining at dex generation time.
// build.gradle — R8 is on by default in release builds
android {
buildTypes {
release {
minifyEnabled true // Enable R8 shrinking/obfuscation
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
'proguard-rules.pro'
}
}
}
R8 can inline small methods, remove unused code, and simplify class hierarchies — all of which reduce the work ART has to do at runtime.
Baseline Profiles: Shipping Your Own Profile
Since Android 9, you can ship a Baseline Profile inside your APK. This tells ART which methods to AOT-compile immediately after install, eliminating the "cold first run" slowdown.
# Generate a baseline profile with Macrobenchmark
./gradlew :app:generateBaselineProfile
# The generated file goes in src/main/baselineProfiles/
Apps with Baseline Profiles see 20–40% faster startup on first launch.
Key Takeaways
| Concept | Detail |
|---|---|
| Dalvik | JIT only; hot methods compiled at runtime, lost between sessions |
| ART initial (5.0) | Full AOT at install; fast runtime, slow installs |
| ART hybrid (7.0+) | JIT first run, profile collected, AOT hot paths in background |
| D8 | Build-time .class → .dex conversion (replaces dx) |
| R8 | Build-time shrink + obfuscate + dex (replaces ProGuard + dx) |
| Baseline Profiles | Ship AOT hints in your APK for fast first-run performance |