Android Runtime
The Android Runtime (ART) is a managed runtime environment that executes Dalvik Executable (DEX) bytecode for Android applications and certain system services on devices running Android 5.0 (API level 21) and later.[1] It replaced the Dalvik virtual machine, which relied on just-in-time (JIT) compilation, by introducing ahead-of-time (AOT) compilation that converts app bytecode into native machine code during installation, thereby enhancing startup times, runtime performance, and battery efficiency.[2] Each Android app operates within its own process, supported by a dedicated ART instance that leverages the underlying Linux kernel for process isolation, threading, and low-level memory management.[1] Originally developed as part of the Android Open Source Project, ART evolved from Dalvik to address limitations in performance and scalability as Android devices grew more powerful.[1] Introduced experimentally in Android 4.4 (KitKat) and made the default runtime in Android 5.0 (Lollipop), ART maintains backward compatibility with Dalvik bytecode, allowing apps optimized for one to generally run on the other, though ART-exclusive features require higher API levels.[2] Key advancements include a hybrid compilation model combining AOT for initial optimization with JIT for runtime adaptations, using profile-guided compilation to refine code based on usage patterns and reduce storage overhead during app updates.[3] ART's design emphasizes efficient garbage collection with a mostly concurrent, compacting collector that minimizes pause times and heap fragmentation, achieving up to 32% smaller heap sizes and 70% faster allocations compared to Android 7.0 in Android 8.0.[4] Subsequent updates, such as those in Android 8.0 (Oreo), introduced loop optimizations like bounds check elimination and SIMD instructions, class hierarchy analysis for better inlining, and faster native interfaces via annotations like@FastNative and @CriticalNative. Further enhancements in later versions, including the introduction of ART Service in Android 14 for modular updates and the Generational Concurrent Mark-Compact Garbage Collector in Android 16 QPR2 (as of October 2025), continue to improve performance, reduce jank, and facilitate debugging with tools such as sampling profilers and detailed exception reporting.[4][5][6]
Overview
Definition and Role
The Android Runtime (ART) is a managed runtime environment that executes Android applications and certain system services by processing Dalvik Executable (DEX) bytecode.[1] It serves as the core execution engine for apps developed primarily in Java or Kotlin, which compile to DEX bytecode compatible with Android's ecosystem.[7] ART's primary role is to translate this platform-agnostic DEX bytecode into native machine code tailored for the device's processor, enabling efficient execution on hardware such as ARM and x86 architectures.[8] This conversion process ensures that Android applications run with optimized performance directly on the underlying hardware, bridging the gap between high-level application code and low-level system resources.[9] Within the Android operating system's layered architecture, ART occupies a central position between the application framework—which provides higher-level APIs for developers—and the Linux kernel, which handles core system operations like hardware abstraction and process management.[9] ART became the default runtime starting with Android 5.0 Lollipop in 2014, succeeding the earlier Dalvik virtual machine to deliver enhanced runtime capabilities across the platform.[8]Key Components
The Android Runtime (ART) consists of several core modular components that enable the execution of Android applications. Central to ART is the runtime library, known as libart.so, which provides the foundational services for loading, verifying, and executing compiled code during app runtime. This library is loaded into the Android system at boot time and handles essential operations such as garbage collection, thread management, and exception handling.[10] A key element in ART's compilation pipeline is the ahead-of-time (AOT) compiler, dex2oat, which converts Dalvik Executable (DEX) bytecode into native machine code optimized for the device's architecture. Dex2oat performs this transformation at install time or during background optimization, ensuring that applications start faster by avoiding initial just-in-time compilation overhead. Integrated within dex2oat is the DEX file format verifier, which conducts rigorous checks on the bytecode to ensure type safety, resource access compliance, and overall integrity before compilation proceeds, thereby preventing runtime errors and enhancing security.[10][11] ART also relies on the Zygote process, which serves as the parent process for all Android application processes. Zygote preloads common framework classes and resources into memory at system startup, allowing new app processes to be efficiently forked from it with minimal overhead, thus improving launch times and resource sharing across applications.[12] The output of dex2oat compilation is stored in the Oat file format, a binary container that holds the compiled native code alongside the original DEX data for quick loading and execution. Oat files enable ART to map executable code directly into process memory, supporting both AOT and hybrid compilation modes without requiring on-the-fly interpretation.[3] Additionally, ART incorporates profile-guided compilation, which leverages runtime usage data collected from application execution to inform optimization decisions. This mechanism allows dex2oat to prioritize frequently used code paths for AOT compilation, dynamically refining performance based on real-world app behavior while balancing storage and battery constraints.[13]History
Origins and Development
The Android Runtime (ART) originated as part of the Android Open Source Project (AOSP), developed by Google specifically for the Android platform as a successor to the Dalvik virtual machine. Dalvik, the original runtime, relied on just-in-time (JIT) compilation, which introduced runtime overhead that affected app startup times and battery efficiency on resource-constrained mobile devices.[1] ART was motivated by these limitations, aiming to deliver faster application launch speeds and reduced power consumption through a shift toward ahead-of-time (AOT) compilation strategies.[1] Experimental development of ART began in the early 2010s, with initial prototypes emphasizing AOT techniques to mitigate Dalvik's JIT drawbacks, such as the overhead of on-device bytecode interpretation and compilation during app execution. By 2013, Google had advanced these efforts sufficiently to integrate an experimental version of ART into Android 4.4 KitKat, where it was made available as a developer option for testing improved performance and garbage collection efficiency.[1] This preview release marked a significant step in addressing Dalvik's challenges, including its resource-intensive garbage collection that could lead to UI stutters and higher battery drain.[1] At Google I/O 2014, Google formally highlighted ART as a performance-focused evolution of the Android runtime, announcing its adoption as the default in the upcoming Android 5.0 Lollipop release.[14] This event underscored ART's role in enhancing overall system responsiveness and energy efficiency, building on the experimental groundwork from KitKat. The development timeline reflected Google's multi-year investment in refining the runtime within AOSP, prioritizing compatibility with existing Dalvik bytecode while introducing optimizations for modern hardware.[1]Introduction and Adoption
The Android Runtime (ART) was introduced experimentally in Android 4.4 KitKat in 2013 as an optional alternative to the Dalvik virtual machine, allowing users to select it via developer options for testing ahead-of-time (AOT) compilation benefits.[1] ART became the default runtime in Android 5.0 Lollipop in 2014, replacing Dalvik's just-in-time (JIT) approach with AOT compilation to enhance app startup times and overall efficiency, while introducing support for 64-bit architectures on ARM, x86, and MIPS hardware. Dalvik bytecode compatibility was retained, allowing existing apps to run on ART.[1][8] By Android 7.0 Nougat in 2016, ART evolved into a hybrid AOT/JIT system for optimized performance, with Dalvik fully phased out.[1] The transition generated OAT files—pre-compiled native executables from DEX bytecode—resulting in larger installed app sizes due to on-device compilation during installation. By Android 10 in 2019, ART supported concurrent compilation using Google Play profiles to pre-compile code paths, reducing install times without blocking the user interface.[1][15] In Android 12 (2021), ART became a mainline module, enabling independent updates via Google Play system updates for delivering optimizations, features, and security fixes without full OS upgrades.[5] Subsequent updates, such as those in Android 13 (2022), improved app startup times by up to 30% on some devices.[16] As of Android 16 (released June 2025), ART includes further performance enhancements and support for modern hardware.[17]Technical Architecture
Compilation Mechanisms
The Android Runtime (ART) primarily employs ahead-of-time (AOT) compilation to convert Dalvik Executable (DEX) bytecode into native machine code, enhancing app performance by avoiding runtime interpretation. This process occurs at install time using the dex2oat tool, which takes DEX files from an APK as input and generates optimized native executables in OAT format.[10][11] The compilation pipeline begins with DEX verification, which applies stricter checks than previous runtimes to ensure bytecode validity, rejecting issues like invalid control flow or unbalanced monitor operations. Verified bytecode then undergoes optimization, including inlining, dead code elimination, and architecture-specific code generation, before outputting an OAT file containing ELF-based native code, along with verification metadata in VDEX format and optional ART startup data. This install-time conversion reduces startup latency and improves execution speed for standard Java/Kotlin code.[10][11] To balance compilation speed with performance, ART incorporates hybrid modes, notably the speed-profile filter introduced in later Android versions. In this mode, dex2oat performs full DEX verification and AOT-compiles only methods identified in a profile (initially derived from cloud data), while optimizing class loading for profiled classes to accelerate installs without full AOT coverage. During runtime, apps collect local profile data on hot methods, which a background daemon uses to recompile the app opportunistically when the device is idle and charging, refining the profile for subsequent optimizations.[10] Although AOT forms the core of ART's approach, just-in-time (JIT) compilation elements are retained as a secondary mechanism for dynamic optimizations on infrequently executed or profile-emergent code paths. The JIT compiler, activated since Android 7.0, profiles running methods and compiles hot ones into native code using runtime-specific information like type feedback, complementing AOT by filling gaps in precompiled binaries without requiring full recompilation. This hybrid setup ensures ongoing performance gains while minimizing storage overhead from exhaustive AOT.[3][10]Runtime Environment
The Android Runtime (ART) manages the execution environment by loading Optimized Ahead-of-Time (OAT) files into memory upon application startup, where these files contain machine code derived from Dalvik Executable (DEX) bytecode.[3] This process begins when an app is launched, triggering ART to map the OAT file directly into the process's address space, avoiding the need for on-the-fly interpretation or compilation if the OAT is present.[3] Class loading occurs through the class linker component, which resolves and initializes classes from the loaded OAT or DEX, linking them into the runtime's object model while verifying type safety and dependencies. Method invocation then proceeds via direct calls to the native machine code embedded in the OAT, enabling efficient execution without bytecode interpretation for compiled portions.[3] Process management in ART relies on the Zygote system process, which serves as the parent for all Android application processes to ensure efficient launching and resource sharing.[12] Spawned early during system boot by the init daemon, Zygote preloads common system libraries, classes, and resources—such as core Java libraries and Android framework components—into its own memory space, reducing startup overhead for child processes.[12] When an app is requested, Zygote forks a new process (or draws from an unspecialized app process pool if enabled), inheriting the preloaded elements and specializing them for the specific application via a Unix domain socket for configuration like process IDs and cgroups.[12] This fork-based model minimizes memory duplication and accelerates app initialization, particularly on devices supporting multiple ABIs.[12] Since Android 12, ART has been integrated as a Project Mainline module, enabling it to receive over-the-air updates through Google Play System Updates. This allows for independent delivery of performance improvements, bug fixes, and security enhancements to the runtime environment on devices running Android 12 (API level 31) and later, without requiring a full operating system update.[5][18] ART supports execution across multiple instruction sets, including ARM64 and x86_64, with architecture-specific optimizations integrated into the OAT generation and loading process.[10] The dex2oat compiler produces OAT files tailored to the target architecture, incorporating optimizations like instruction selection and register allocation suited to ARM64's AArch64 or x86_64's extensions, ensuring compatibility and performance on diverse hardware.[10] For instance, 64-bit compilation can be enabled via properties likedalvik.vm.dex2oat64.enabled on supported devices, allowing ART to leverage architecture-native features during runtime execution.[10]
To accelerate method dispatch, ART employs inline caching, which captures runtime type information at call sites and embeds it into profiles for subsequent optimizations.[4] Introduced in Android 8.0, this mechanism records frequent receiver types during execution, enabling the compiler to devirtualize calls—replacing dynamic lookups with direct native invocations—and store the cache directly in OAT files for reuse across app sessions.[4] By integrating with class hierarchy analysis, inline caching reduces dispatch overhead, particularly for polymorphic methods, without requiring full recompilation.[4]