androidengineers.Book a session

Android Architecture Fundamentals

ART vs Dalvik: A Practical Comparison

article20 minMedium

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)
  • .oat files 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:

FilterWhat it doesUsed when
verifyJust verify bytecode, no compilationInstall time (fast)
quickenQuicken interpreter opcodesRarely
spaceCompile, optimize for sizeStorage-constrained
speedFull AOT compilationSystem apps, forced
speed-profileAOT only hot methods from profileDefault for user apps after profiling
everythingAOT everythingTesting

R8 and D8: Your Build-Time Compilers

These run during your build, before the device ever sees your code:

  • D8 (replaces dx): Converts .class bytecode 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

ConceptDetail
DalvikJIT 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
D8Build-time .class → .dex conversion (replaces dx)
R8Build-time shrink + obfuscate + dex (replaces ProGuard + dx)
Baseline ProfilesShip AOT hints in your APK for fast first-run performance

YOUR LEARNING JOURNEY

0 of 177 available lessons completed

Progress saved in this browser. No account needed.
ART vs Dalvik: A Practical Comparison | Android System Design | Android Engineers