Android Runtime, Dalvik, and Dex Compiler
Android Runtime, Dalvik, and Dex Compiler
Android applications go through a unique compilation and execution pipeline before running on a device. The Android Runtime (ART), its predecessor Dalvik, and the Dex Compiler each play a role in transforming application code into an optimized format that runs efficiently on constrained hardware. Understanding how these components interact is a common interview topic because it reveals how the platform manages performance, memory, and backward compatibility at the system level. By the end of this lesson, you will be able to:
- Explain the difference between Ahead of Time and Just in Time compilation strategies.
- Describe how ART replaced Dalvik and the performance benefits that followed.
- Explain what the Dex Compiler produces and why the
.dexformat exists. - Identify how multi-dex support addresses the 64K method limit.
- Describe how profile guided optimization combines AOT and JIT in modern ART.
Just in Time Compilation in Dalvik
Dalvik was the original runtime used in Android from version 1.0 through Android 4.4. It is a register based virtual machine designed for devices with limited memory and processing power. Unlike the stack based Java Virtual Machine, Dalvik uses register based instructions, which reduces the number of instructions executed per operation.
Dalvik uses Just in Time (JIT) compilation. When the application runs, Dalvik interprets bytecode and compiles frequently executed code paths (hot spots) into native machine code at runtime. This means every time the app starts, the runtime must rediscover and recompile those hot paths:
// Dalvik interprets this bytecode on each launch
// and JIT-compiles hot loops at runtime
fun computeSum(items: List<Int>): Int {
var sum = 0
for (item in items) {
sum += item
}
return sum
}
JIT compilation reduces installation time because no compilation happens during install. However, it increases CPU usage during execution and causes slower startup because the runtime has not yet identified and compiled the hot paths. Each application restart repeats this warmup process, meaning Dalvik provides no cumulative performance improvement across launches.
Dalvik also used a limited trace based JIT compiler that compiled only individual execution traces (hot code paths) rather than entire methods. This approach required less memory than method based JIT but produced less optimal machine code because the compiler could not reason about the full method structure for optimization decisions.
Ahead of Time Compilation in ART
Android Runtime (ART) replaced Dalvik as the default runtime starting with Android 5.0. The primary change was the introduction of Ahead of Time (AOT) compilation using the dex2oat tool. During app installation, ART compiles the entire application bytecode into native machine code stored in .oat files. This eliminates the need for runtime interpretation and JIT compilation on first launch:
// After dex2oat runs at install time, this function
// exists as native machine code on disk
fun computeSum(items: List<Int>): Int {
var sum = 0
for (item in items) {
sum += item
}
return sum
}
The tradeoff is longer installation times and more storage space, because the compiled native code is larger than the original bytecode. For large applications, the installation time could increase significantly because dex2oat had to compile all methods regardless of whether they would ever be executed.
This interview continues for subscribers
Subscribe to Dove Letter for full access to exclusive interviews about Android and Kotlin development.
Become a Sponsor