AOT (Ahead-Of-Time) — a compilation technology where source code or bytecode is converted into machine instructions before program execution, at the build or installation stage. In Android, AOT compilation became a key innovation of the ART runtime environment, which replaced Dalvik in version 5.0 Lollipop. According to Google, 2024, AOT compilation in ART eliminates warm-up delays and reduces application power consumption by 10–15% compared to the JIT approach.
Key Takeaways
Ahead-Of-Time (AOT) is a compilation method where a program is converted into machine code before it is run. The term “Ahead-Of-Time” contrasts with JIT (Just-In-Time): if JIT compiles “just in time,” then AOT compiles “ahead of time.” An AOT compiler takes source code or an intermediate representation (bytecode) as input and generates an executable file ready to run.
The history of AOT dates back to traditional C and C++ compilers, where compilation always happens before execution. In the context of managed languages (Java, C#, Dart), AOT is a more recent innovation: for a long time, it was believed that dynamic capabilities (reflection, dynamic class loading) made AOT difficult to implement. Google solved this problem for Android by creating dex2oat — an AOT compiler of DEX bytecode into native code.
An AOT compiler performs a full translation cycle. The first stage is parsing and building an abstract syntax tree (AST). The second is analysis and optimization: dead code elimination, inlining, loop optimization. The third is generating machine code for the target architecture (ARM, ARM64, x86). The result is an executable file that requires no additional processing at runtime.
# Manual launch of AOT compiler dex2oat
dex2oat --dex-file=classes.dex \
--oat-file=classes.oat \
--arch=arm64 \
--instruction-set-variant=generic
# Check compiled OAT file
oatdump --oat-file=classes.oat --output=oat_dump.txt
In Android, AOT compilation is implemented through the dex2oat utility (dalvik executable to optimized android translator). When a user installs an application, the system runs dex2oat, which reads DEX files from the APK, optimizes the bytecode, and creates an OAT file — an ELF binary with native code. This file is saved in the /data/dalvik-cache/ partition.
The compilation process includes several levels of optimization. The basic level — bytecode verification and basic optimizations (dead code elimination, constant folding). The intermediate level — method inlining, loop unrolling, escape analysis. The maximum level — global optimizations of the entire application, including devirtualization and stack size optimization. The optimization level depends on the compilation mode (speed, speed-profile, space).
An OAT file uses the ELF (Executable and Linkable Format) format — the same format used by native Linux binaries. Inside the OAT file is the compiled code for each application method, along with metadata: information about classes, fields, methods, and their relationships. ART uses this metadata for fast class loading and resolving symbolic references without full DEX parsing.
| OAT Component | Purpose |
|---|---|
| ELF header | ELF format header |
| Code section | Machine code of compiled methods |
| OAT header | ART metadata: version, section sizes |
| DEX sections | Original DEX data for reflection |
| Link table | Link table for JNI and native libraries |
AOT and JIT represent different points in the trade-off space between performance and flexibility. AOT provides maximum execution speed from the first second but requires more disk space and installation time. JIT saves space and installation time but pays with warm-up delays and peak power consumption.
The key selection factor is the use case. For applications that are launched once and run for a long time (games, editors, navigation), AOT is preferable — the compilation costs are offset by stable performance. For small utilities that are rarely launched and run for short periods, JIT may be more advantageous — fast installation and small footprint are more important than peak performance.
| Criterion | AOT | JIT |
|---|---|---|
| Startup | Instant | With warm-up |
| Installation | Slower (compilation) | Fast |
| Disk space | +15–30% | Minimal |
| Power consumption | Stable | Peaks during compilation |
| Adaptability | Low | High |
An interesting nuance: AOT code is not always faster than JIT. JIT has access to runtime profiling information — precise object types, call frequencies, real branching patterns. This allows applying optimizations unavailable to AOT (e.g., profile-guided inlining). In practice, the performance difference of compiled code between AOT and JIT is ±5–10% depending on the scenario.
AOT provides three key advantages for mobile applications. First — predictable performance. The user doesn’t see “stuttering” in the first seconds: the application runs at maximum speed from the first frame. This is critical for games, animations, and interfaces with smooth transitions.
Second — energy efficiency. AOT doesn’t create peak CPU loads typical of JIT compilation. The processor operates in a stable mode, reducing power consumption by 10–15% during the first 30–60 seconds of application usage. For a typical user launching 20–30 apps per day, this provides a noticeable increase in battery life.
AOT compilation simplifies the runtime environment. When all code is already compiled, there is no need for a JIT compiler, interpreter, or profiler at runtime. This reduces the size of the runtime itself and lowers the chance of errors. ART in full AOT mode uses approximately 15% less RAM than a similar environment with active JIT.
The main disadvantage of AOT is installation time. On early devices with Android 5.0, installing large applications (100–200 MB) could take 2–5 minutes due to AOT compilation. This created a negative user experience: after downloading the APK, users had to wait before opening the application. Google partially solved this problem in Android 7.0 by switching to a hybrid scheme.
The second disadvantage is disk space. OAT files are 15–30% larger than the original DEX files. On devices with 8–16 GB of internal storage, each application “eats” additional space on the system partition. For users with a large number of installed applications (50–100), this can lead to insufficient space for system updates.
AOT code is fixed at compile time. If the application uses different execution patterns depending on the Android version, device model, or user settings, AOT cannot adapt. Optimizations chosen for one scenario may be suboptimal for another. JIT is more flexible in this regard: it recompiles hot methods when execution conditions change.
AOT compilation is used not only in Android. Flutter uses AOT to compile Dart code into native code for iOS and Android. This ensures UI performance at 60 fps even on low-end devices. During development, Flutter uses JIT (hot reload), and for release builds — AOT, combining the advantages of both approaches.
In the .NET ecosystem, the ReadyToRun (R2R) technology allows compiling assemblies into native code ahead of time. This reduces .NET application startup time by 30–50%. The Go compiler is inherently an AOT compiler: Go programs are compiled into a single static binary with no external dependencies, making them ideal for container environments.
// Flutter: AOT compilation of Dart into native code
// Release build uses AOT
flutter build apk --release
// Result: libapp.so with AOT-compiled Dart code
// Development uses JIT (hot reload)
flutter run
An additional advantage of AOT is making reverse engineering harder. Compiled native code is more difficult to decompile than bytecode. Tools like JADX and APKTool work with the DEX format but cannot recover source code from OAT files at the same level of detail. This doesn’t replace obfuscation (ProGuard, R8), but creates an additional barrier for analyzers.
The modern standard in Android is profiled AOT compilation, implemented in ART starting with Android 7.0. When installing, the application is not fully compiled — instead, fast bytecode verification and JIT are used for the first launches. This solves the long installation problem characteristic of pure AOT in Android 5.0–6.0.
After 2–3 application launches, the ART profiler collects data about real usage and determines which methods are most critical for performance. Then, in the background (usually at night when the device is charging), dex2oat compiles these hot methods into native code. After background compilation, the application achieves performance equivalent to full AOT, without negatively impacting the user experience during installation.
// Programmatic control of compilation mode (Android 9+)
fun requestProfileCompilation(context: Context) {
val pm = context.packageManager
// It is recommended to use profiled compilation
pm.setComponentEnabledSetting(
ComponentName(context, javaClass()),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP
)
}
To maximize the benefits of hybrid compilation, developers should follow a few rules. Use baseline profiles — pre-collected profiles that ship with the APK and allow ART to start AOT compilation of hot methods immediately after installation. Baseline profiles reduce the time to reach full performance from 2–3 launches to the very first launch.
Frequently Asked Questions
AOT is converting a program into machine code in advance, before the user runs it. Imagine that a book is translated entirely into your language before you open it — you read it immediately, without delays for page translation.
AOT compiles code during installation (slower installation, but faster startup). JIT compiles code at runtime (fast installation, but the first seconds are slower). Modern systems combine both approaches.
Google wanted to eliminate the JIT warm-up problem — delays in the first seconds of application execution. AOT compilation in ART provided instant startup and reduced power consumption, which was critically important for mobile devices.
The APK size doesn’t change — AOT compilation creates OAT files on the system partition that are 15–30% larger than the original DEX files. The user sees this as a reduction in free internal storage space, not as an increase in the download file size.
This is a hybrid approach where the first launches of the application use JIT, and then the system compiles only frequently used methods into native code in the background. This combines the fast installation of JIT with the high performance of AOT.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also