This page discusses how to configure ART and its compilation options. Topics addressed here include configuration of pre-compilation of the system image, dex2oat compilation options, and how to trade off system partition space, data partition space, and performance.
See ART and Dalvik, the Dalvik Executable format, and the remaining pages on source.android.com to work with ART. See Verifying App Behavior on the Android Runtime (ART) to ensure your apps work properly.
How ART works
ART uses ahead-of-time (AOT) compilation, and starting in Android 7.0 (Nougat or N), it uses a hybrid combination of AOT, just-in-time (JIT) compilation, and profile-guided compilation. The combination of all these compilation modes is configurable and will be discussed in this section. As an example, Pixel devices are configured with the following compilation flow:
- An application is initially installed without any AOT compilation. The first few times the application runs, it is interpreted, and methods frequently executed are JIT compiled.
- When the device is idle and charging, a compilation daemon runs to AOT-compile frequently used code based on a profile generated during the first runs.
- The next restart of an application uses the profile-guided code and avoid doing JIT compilation at runtime for methods already compiled. Methods that get JIT-compiled during the new runs are added to the profile, which will then be picked up by the compilation daemon.
ART comprises a compiler (the dex2oat
tool) and a runtime
(libart.so
) that is loaded for starting the Zygote. The
dex2oat
tool takes an APK file and generates one or more
compilation artifact files that the runtime loads. The number of files, their
extensions, and names are subject to change across releases, but as of the
Android 8 release, the files being generated are:
.vdex
: contains the uncompressed DEX code of the APK, with some additional metadata to speed up verification..odex
: contains AOT compiled code for methods in the APK..art (optional)
: contains ART internal representations of some strings and classes listed in the APK, used to speed application startup.
Compilation options
Compilation options for ART are of two categories:
- System ROM configuration: what code gets AOT-compiled when building a system image.
- Runtime configuration: how ART compiles and runs applications on a device.
One core ART option to configure these two categories is compiler
filters. Compiler filters drive how ART compiles DEX code and is an
option passed to the dex2oat
tool. Starting in Android 8,
there are four officially supported filters:
verify
: only run DEX code verification.quicken
: (removed since Android 12) run DEX code verification and optimize some DEX instructions to get better interpreter performance.speed
: run DEX code verification and AOT-compile all methods.speed-profile
: run DEX code verification and AOT-compile methods listed in a profile file.
System ROM configuration
There are a number of ART build options available for configuring a system ROM. How you configure these options depends on the available storage space for the system image and the number of pre-installed applications. The JARs/APKs that are compiled into a system ROM can be divided in four categories:
- Boot classpath code: compiled with the
speed-profile
compiler filter by default. - System server code (see
PRODUCT_SYSTEM_SERVER_JARS
,PRODUCT_APEX_SYSTEM_SERVER_JARS
,PRODUCT_STANDALONE_SYSTEM_SERVER_JARS
,PRODUCT_APEX_STANDALONE_SYSTEM_SERVER_JARS
later in this document):- (since Android 14 (AOSP experimental)) compiled with the
speed-profile
compiler filter by default, or compiled with thespeed
compiler filter if a profile isn't provided. - (until Android 13) compiled with the
speed
compiler filter by default.
PRODUCT_SYSTEM_SERVER_COMPILER_FILTER
(see later in this document). - (since Android 14 (AOSP experimental)) compiled with the
- Product-specific core applications (see
PRODUCT_DEXPREOPT_SPEED_APPS
later in this document): compiled with thespeed
compiler filter by default. - All other applications: compiled with the
speed-profile
compiler filter by default, or compiled with theverify
compiler filter if a profile isn't provided.Configurable through
PRODUCT_DEX_PREOPT_DEFAULT_COMPILER_FILTER
(see later in this document).
Makefile options
WITH_DEXPREOPT
DONT_DEXPREOPT_PREBUILTS
(since Android 5)PRODUCT_DEX_PREOPT_DEFAULT_COMPILER_FILTER
(since Android 9)WITH_DEXPREOPT_BOOT_IMG_AND_SYSTEM_SERVER_ONLY
(new in Android 8 MR1)LOCAL_DEX_PREOPT
PRODUCT_DEX_PREOPT_BOOT_FLAGS
PRODUCT_DEX_PREOPT_DEFAULT_FLAGS
PRODUCT_DEX_PREOPT_MODULE_CONFIGS
PRODUCT_DEXPREOPT_SPEED_APPS (New in Android 8)
PRODUCT_SYSTEM_SERVER_APPS (New in Android 8)
PRODUCT_ART_TARGET_INCLUDE_DEBUG_BUILD(Post Android 8)
WITH_DEXPREOPT_PIC (Removed in Android 8)
WITH_DEXPREOPT_BOOT_IMG_ONLY
(removed in Android 8 MR1)PRODUCT_SYSTEM_SERVER_COMPILER_FILTER
- (since Android 14 (AOSP experimental)) If unspecified, the
speed-profile
compiler filter is used, or thespeed
compiler filter is used if a profile isn't provided. - (until Android 13) If unspecified, the
speed
compiler filter is used. - If set to
speed
, thespeed
compiler filter is used. - If set to
speed-profile
, thespeed-profile
compiler filter is used, or theverify
compiler filter is used if a profile isn't provided. - If set to
verify
, theverify
compiler filter is used. PRODUCT_SYSTEM_SERVER_JARS
,PRODUCT_APEX_SYSTEM_SERVER_JARS
,PRODUCT_STANDALONE_SYSTEM_SERVER_JARS
,PRODUCT_APEX_STANDALONE_SYSTEM_SERVER_JARS
- (required)
PRODUCT_SYSTEM_SERVER_JARS
: List of system server classpath jars on the platform (i.e., as part ofSYSTEMSERVERCLASSPATH
). Adding system server classpath jars to this list is required. Failing to add system server classpath jars to the list results in those jars not being loaded. - (required)
PRODUCT_APEX_SYSTEM_SERVER_JARS
: List of system server classpath jars delivered via apex (i.e., as part ofSYSTEMSERVERCLASSPATH
). The format is<apex name>:<jar name>
. Adding apex system server classpath jars to this list is required. Failing to add apex system server classpath jars to this list results in those jars not being loaded. - (optional, since Android 13)
PRODUCT_STANDALONE_SYSTEM_SERVER_JARS
: List of jars that system server loads dynamically using separate classloaders (throughSystemServiceManager.startServiceFromJar
). Adding standalone system server jars to this list isn't required but strongly recommended because it makes the jars compiled and therefore have a good runtime performance. - (required, since Android 13)
PRODUCT_APEX_STANDALONE_SYSTEM_SERVER_JARS
: List of jars delivered via apex that system server loads dynamically using separate classloaders (i.e., throughSystemServiceManager.startServiceFromJar
or declared as<apex-system-service>
). The format is<apex name>:<jar name>
. Adding standalone apex system server jars to this list is required. Failing to add standalone apex system server jars to this list results in boot failure. - Preloaded Classes List
Whether dex2oat
is invoked on DEX code installed on the system image. Enabled by default.
Enabling DONT_DEXPREOPT_PREBUILTS
prevents the prebuilts from being
pre-optimized. These are apps that have include $(BUILD_PREBUILT)
specified in their Android.mk
. Skipping
pre-optimization of prebuilt apps that are likely to be updated via Google Play
saves space in the system image but does add to first boot time. Note that this option has no effect
on prebuilt apps defined in Android.bp
.
PRODUCT_DEX_PREOPT_DEFAULT_COMPILER_FILTER
specifies the default compiler filter
for pre-optimized applications. These apps are defined in Android.bp
or have
include $(BUILD_PREBUILT)
specified in their Android.mk
. If unspecified,
the default value is speed-profile
, or verify
if the value is unspecified
and a profile isn't provided.
Enabling WITH_DEXPREOPT_BOOT_IMG_AND_SYSTEM_SERVER_ONLY
pre-optimizes only the
boot classpath and system server jars.
Pre-optimization can also be enabled or disabled on an individual app basis by
specifying the LOCAL_DEX_PREOPT
option in the module definition.
This can be useful for disabling pre-optimization of apps that may immediately
receive Google Play updates since the updates would render the pre-optimized
code in the system image obsolete. This is also useful to save space on major
version upgrade OTAs since users may already have newer versions of apps in the
data partition.
LOCAL_DEX_PREOPT
supports the values ‘true’ or ‘false’ to
enable or disable pre-optimization, respectively. In addition, ‘nostripping’ can
be specified if pre-optimization should not strip the classes.dex
file from the APK or JAR file. Normally this file is stripped since it’s no
longer needed after pre-optimization, but this last option is necessary to
allow third-party APK signatures to remain valid.
Passes options to dex2oat
to control how the boot image is
compiled. It can be used to specify customized image classes lists, compiled
classes lists, and compiler filters.
Passes options to dex2oat
to control how everything besides the
boot image is compiled.
Provides the ability to pass dex2oat
options for a particular
module and product configuration. It is set in a product’s
device.mk
file by $(call add-product-dex-preopt-module-config,<modules>,<option>)
where <modules>
is a list of LOCAL_MODULE and LOCAL_PACKAGE names
for JAR and APK files, respectively.
List of applications that have been identified as core to the products and
which are desirable to compile with the speed
compiler filter. For
example, persistent apps such as SystemUI get a chance to use
profile-guided compilation only at the next reboot, so it may be better for the
product to have these apps always AOT-compiled.
List of applications that are loaded by the system server. These applications
are compiled by default with the speed
compiler filter.
Whether to include a debug version of ART on the device. By default, this is
enabled for userdebug and eng builds. The behavior can be overridden by explicitly
setting the option to true
or false
.
By default, the device uses the non-debug version (libart.so
).
To switch, set the system property persist.sys.dalvik.vm.lib.2
to
libartd.so
.
In Android 5.1.0 through Android 6.0.1, WITH_DEXPREOPT_PIC
can
be specified to enable position-independent code (PIC). With this, compiled
code from the image doesn’t have to be relocated from /system into
/data/dalvik-cache, saving space in the data partition. However, there is a
slight runtime impact because it disables an optimization that takes advantage
of position-dependent code. Typically, devices wanting to save space in /data
should enable PIC compilation.
In Android 7.0, PIC compilation was enabled by default.
This option was replaced with WITH_DEXPREOPT_BOOT_IMG_AND_SYSTEM_SERVER_ONLY that also preopts the system server jars.
This option specifies the compiler filter for system server.
The following are lists of jars that are loaded by system server. The jars are compiled with the
compiler filter specified by PRODUCT_SYSTEM_SERVER_COMPILER_FILTER
Boot classpath configuration
The preloaded classes list is a list of classes the zygote initializes on
startup. This saves each app from having to run these class initializers
separately, allowing them to start up faster and share pages in memory. The
preloaded classes list file is located at frameworks/base/config/preloaded-classes
by default, and it contains a list that's tuned for typical phone use. This might
be different for other devices such as wearables, and must be tuned
accordingly. Be careful when tuning this; adding too many classes wastes
memory when unused classes get loaded. Adding too few classes forces each app to
have to have its own copy, which again, wastes memory.
Example usage (in product’s device.mk):
PRODUCT_COPY_FILES += <filename>:system/etc/preloaded-classes
Note: This line must be placed before
inheriting any product configuration makefiles that get the default one from:
build/target/product/base.mk
Runtime configuration
Jit options
The following options affect Android releases only where the ART JIT compiler is available.
- dalvik.vm.usejit: whether or not the JIT is enabled.
- dalvik.vm.jitinitialsize (default 64K): the initial capacity of the code cache. The code cache will regularly GC and increase if needed.
- dalvik.vm.jitmaxsize (default 64M): the maximum capacity of the code cache.
- dalvik.vm.jitthreshold: (default 10000) - This is the threshold that the "hotness" counter of a method needs to pass in order for the method to be JIT compiled. The "hotness" counter is a metric internal to the runtime. It includes the number of calls, backward branches, and other factors.
- dalvik.vm.usejitprofiles: whether or not
JIT profiles are enabled; this may be used even if dalvik.vm.usejit is false.
Note that if this is false, the compiler filter
speed-profile
does not AOT-compile any method and is equivalent toverify
. - dalvik.vm.jitprithreadweight (default to dalvik.vm.jitthreshold / 20) - The weight of the JIT "samples" (see jitthreshold) for the application UI thread. Use to speed up compilation of methods that directly affect users experience when interacting with the app.
- dalvik.vm.jittransitionweight: (default to dalvik.vm.jitthreshold / 10) the weight of the method invocation that transitions between compile code and interpreter. This helps make sure the methods involved are compiled to minimize transitions (which are expensive).
Package manager options
Since Android 7.0, there's a generic way to specify the level of compilation/verification that happened at various stages. The compilation levels can be configured via system properties with the defaults being:
pm.dexopt.install=speed-profile
pm.dexopt.bg-dexopt=speed-profile
pm.dexopt.boot-after-ota=verify
pm.dexopt.first-boot=verify
-
The compilation filter for the first time the device ever boots. The filter used here only affects the boot time after factory. We recommend the filter
verify
for it to avoid long times before a user gets to use the phone for the very first time. Note that if all applications in the system image are already compiled withverify
,speed-profile
, orspeed
with the right class loader context,pm.dexopt.first-boot
will have no effect.
This is the compilation filter used when installing applications through Google Play. We recommend the install filter be set to speed-profile in order to enable the use of profiles from the dex metadata files. Note that if a profile isn't provided or if it is empty speed-profile is equivalent to verify.
This is the compilation filter used when the device is idle, charging and
fully charged. Try the speed-profile
compiler filter
to take advantage of profile-guided compilation and save on storage.
The compilation filter used after an over-the-air update. We
strongly recommend the verify
compiler filter for this
option to avoid very long boot times.
Dex2oat options
Note that these options affect dex2oat
during on-device compilation as well as during pre-optimization, whereas most
of the options discussed above affect only pre-optimization.
To control dex2oat
while it’s compiling the boot image:
- dalvik.vm.image-dex2oat-Xms: initial heap size
- dalvik.vm.image-dex2oat-Xmx: maximum heap size
- dalvik.vm.image-dex2oat-filter: compiler filter option
- dalvik.vm.image-dex2oat-threads: number of threads to use
To control dex2oat
while it’s compiling everything besides the boot image:
- dalvik.vm.dex2oat-Xms: initial heap size
- dalvik.vm.dex2oat-Xmx: maximum heap size
- dalvik.vm.dex2oat-filter: compiler filter option
On releases through Android 6.0, one additional option is provided for compiling everything besides the boot image:
- dalvik.vm.dex2oat-threads: number of threads to use
Starting with Android 6.1, this becomes two additional options for compiling everything besides the boot image:
- dalvik.vm.boot-dex2oat-threads: number of threads to use during boot time
- dalvik.vm.dex2oat-threads: number of threads to use after boot time
Starting with Android 7.1, two options are provided for controlling how memory is used when compiling everything besides the boot image:
- dalvik.vm.dex2oat-very-large: minimum total dex file size in bytes to disable AOT compilation
- dalvik.vm.dex2oat-swap: use dex2oat swap file (for low-memory devices)
The options that control initial and maximum heap size for
dex2oat
should not be reduced since they could limit what
applications can be compiled.
Starting with Android 11, three CPU affinity options are provided to allow compiler threads to be restricted to a specific group of CPUs:
- dalvik.vm.boot-dex2oat-cpu-set: CPUs running dex2oat threads during boot time
- dalvik.vm.image-dex2oat-cpu-set: CPUs running dex2oat while compiling the boot image
- dalvik.vm.dex2oat-cpu-set: CPUs running dex2oat threads after boot time
The CPUs should be specified as a comma-separated list of CPU ids. For example to run on dex2oat on the CPUs 0-3, set:
dalvik.vm.dex2oat-cpu-set=0,1,2,3
When setting the CPU affinity properties, we recommend matching the corresponding property for the number of dex2oat threads to match the number CPUs selected to avoid unnecessary memory and I/O contention:
dalvik.vm.dex2oat-cpu-set=0,1,2,3 dalvik.vm.dex2oat-threads=4
Starting with Android 12, the following options were added:
- dalvik.vm.ps-min-first-save-ms: the time to wait for the runtime to generate a profile of the application, the first time the application is launched
- dalvik.vm.ps-min-save-period-ms: the minimum time to wait before updating the profile of an app
- dalvik.vm.systemservercompilerfilter: the compiler filter that the device uses when recompiling system server
A/B specific configuration
ROM configuration
Starting in Android 7.0, devices may use two system partitions to enable A/B system updates. To save on the system partition size, the preopted files can be installed in the unused second system partition. They are then copied to the data partition on first boot.
Example usage (in device-common.mk
):
PRODUCT_PACKAGES += \ cppreopts.sh PRODUCT_PROPERTY_OVERRIDES += \ ro.cp_system_other_odex=1
And in device's BoardConfig.mk
:
BOARD_USES_SYSTEM_OTHER_ODEX := true
Note that boot classpath code, system server code, and product-specific core
applications always compile to the system partition. By default, all other
applications get compiled to the unused second system partition. This can be
controlled with the SYSTEM_OTHER_ODEX_FILTER
, which has a value by
default of:
SYSTEM_OTHER_ODEX_FILTER ?= app/% priv-app/%
Background dexopt OTA
With A/B enabled devices, applications can be compiled in the background for updating to the new system image. See App compilation in background to optionally include the compilation script and binaries in the system image. The compilation filter used for this compilation is controlled with:
pm.dexopt.ab-ota=speed-profile
We recommend using speed-profile
to take advantage of profile guided
compilation and save on storage.