ART を設定する

このページでは、ART とそのコンパイル オプションを設定する方法について説明します。ここで扱うトピックは、システム イメージの事前コンパイルの構成、dex2oat のコンパイル オプション、システム パーティションおよびデータ パーティションの容量とパフォーマンスをトレードオフする方法などです。

ART の操作については、ART と DalvikDalvik 実行可能ファイルの形式、および source.android.com のその他のページをご覧ください。アプリが正しく動作することを確認するには、Android ランタイム(ART)でのアプリの動作確認をご覧ください。

ART の仕組み

ART は事前(AOT)コンパイルを使用し、Android 7.0(Nougat または N)以降では AOT コンパイル、ジャストインタイム(JIT)コンパイル、プロファイル ガイド付きコンパイルを組み合わせて使用します。これらすべてのコンパイル モードの組み合わせは構成可能です。以下のセクションではそれについて説明します。たとえば、Pixel デバイスの場合は、以下のコンパイル フローを使用して構成を行います。

  1. 最初に、アプリは AOT コンパイルなしでインストールされます。最初の数回の実行では、アプリはインタープリタによって解釈され、頻繁に実行されるメソッドは JIT コンパイルされます。
  2. デバイスがアイドル状態で充電中のときに、コンパイル デーモンが実行され、初回実行時に生成されたプロファイルに基づいて、頻繁に使用されるコードが AOT コンパイルされます。
  3. アプリを次に再起動すると、プロファイル ガイド付きコードが使用されます。これにより、コンパイル済みのメソッドについては実行時の JIT コンパイルが回避されます。新規の実行時に新たに JIT コンパイルされたメソッドはプロファイルに追加され、コンパイル デーモンによってピックアップされます。

ART は、コンパイラ(dex2oat ツール)と、Zygote を起動するために読み込まれるランタイム(libart.so)で構成されます。dex2oat ツールは APK ファイルを受け取り、ランタイムが読み込む 1 つ以上のコンパイル アーティファクト ファイルを生成します。ファイルの数や拡張子、名前はリリースによって異なる場合がありますが、Android 8 以降のリリースの場合、以下のファイルが生成されます。

  • .vdex: APK の非圧縮 DEX コードと、検証を高速化するための追加メタデータを格納します。
  • .odex: APK 内のメソッドの AOT コンパイル済みコードを含みます。
  • .art (optional): アプリの起動を高速化するために使用される、APK にリストされた文字列とクラスの ART 内部表現を格納します。

コンパイル オプション

ART のコンパイル オプションには、次の 2 つのカテゴリがあります。

  1. システム ROM 構成: システム イメージのビルド時にどのコードを AOT コンパイルするか。
  2. 実行時構成: ART がデバイス上でアプリをどのようにコンパイルして実行するか。

上記の 2 つのカテゴリを構成するコア ART オプションの一つは、コンパイラ フィルタです。コンパイラ フィルタは ART が DEX コードをコンパイルする方法を制御するオプションであり、dex2oat ツールに渡されます。Android 8 以降、4 つのフィルタが公式にサポートされています。

  • verify: DEX コードの検証のみを実行します。
  • quicken: (Android 12 以降で削除)DEX コードの検証を実行し、DEX 命令の一部を最適化してインタープリタのパフォーマンスを向上させます。
  • speed: DEX コードの検証を実行し、すべてのメソッドを AOT コンパイルします。
  • speed-profile: DEX コードの検証を実行し、プロファイル ファイルにリストされているメソッドを AOT コンパイルします。

システム ROM 構成

システム ROM を構成する際は、いくつかの ART ビルド オプションを使用できます。これらのオプションを構成する方法は、システム イメージの使用可能な保存容量と、プリインストールされたアプリの数に応じて決まります。システム ROM にコンパイルされる JAR / APK は、以下の 4 つのカテゴリに分けられます。

  • ブート クラスパス コード: デフォルトでは、speed-profile コンパイラ フィルタでコンパイルされます。
  • システム サーバーコード(このドキュメントの後半の PRODUCT_SYSTEM_SERVER_JARSPRODUCT_APEX_SYSTEM_SERVER_JARSPRODUCT_STANDALONE_SYSTEM_SERVER_JARSPRODUCT_APEX_STANDALONE_SYSTEM_SERVER_JARS を参照):
    • (Android 14(AOSP 試験運用版)以降)デフォルトでは、speed-profile コンパイラ フィルタでコンパイルされます。プロファイルが指定されていない場合は、speed コンパイラ フィルタでコンパイルされます。
    • (Android 13 まで)デフォルトでは、speed コンパイラ フィルタでコンパイルされます。
    PRODUCT_SYSTEM_SERVER_COMPILER_FILTER で構成できます(このドキュメントの後半を参照)。
  • プロダクト固有のコアアプリ(このドキュメントの後半の PRODUCT_DEXPREOPT_SPEED_APPS を参照): デフォルトでは、speed コンパイラ フィルタでコンパイルされます。
  • 他のすべてのアプリ: デフォルトでは、speed-profile コンパイラ フィルタでコンパイルされます。プロファイルが指定されていない場合は、verify コンパイラ フィルタでコンパイルされます。

    PRODUCT_DEX_PREOPT_DEFAULT_COMPILER_FILTER で構成できます(このドキュメントの後半を参照)。

メイクファイル オプション

  • WITH_DEXPREOPT
  • dex2oat がシステム イメージにインストールされた DEX コードで呼び出されるかどうか。デフォルトで有効。

  • DONT_DEXPREOPT_PREBUILTS(Android 5 以降)
  • DONT_DEXPREOPT_PREBUILTS を有効にすると、事前ビルド済みアプリの事前最適化を回避できます。そのようなアプリには、Android.mkinclude $(BUILD_PREBUILT) が指定されているアプリがあります。Google Play でアップデートされる可能性がある事前ビルド済みアプリの事前最適化をスキップすると、システム イメージの容量は節約されますが、初回の起動時間が長くなります。このオプションは、Android.bp で定義された事前ビルド済みアプリには効果を持ちません。

  • PRODUCT_DEX_PREOPT_DEFAULT_COMPILER_FILTER(Android 9 以降)
  • PRODUCT_DEX_PREOPT_DEFAULT_COMPILER_FILTER は、事前最適化済みアプリのデフォルトのコンパイラ フィルタを指定します。そのようなアプリは、Android.bp で定義されているか、Android.mkinclude $(BUILD_PREBUILT) が指定されています。コンパイラ フィルタを指定しないと、デフォルト値は speed-profile になります。値が指定されず、プロファイルが指定されていない場合は、verify になります。

  • WITH_DEXPREOPT_BOOT_IMG_AND_SYSTEM_SERVER_ONLY(Android 8 MR1 で導入)
  • WITH_DEXPREOPT_BOOT_IMG_AND_SYSTEM_SERVER_ONLY を有効にすると、ブート クラスパスとシステム サーバーの JAR だけが事前最適化されます。

  • LOCAL_DEX_PREOPT
  • モジュール定義内で LOCAL_DEX_PREOPT オプションを指定することにより、個別のアプリ単位で事前最適化を有効 / 無効にすることもできます。これは、Google Play のアップデートによりシステム イメージ内の事前最適化済みコードが陳腐化する場合に備えて、アップデートを即座に受信する可能性があるアプリの事前最適化を無効にするのに有用な場合があります。また、データ パーティションに新しいバージョンのアプリがすでに存在する場合は、メジャー バージョン アップグレード OTA の容量を節約するためにも役立ちます。

    LOCAL_DEX_PREOPT では、true または false の値を使用して事前最適化を有効または無効にできます。また、事前最適化で APK または JAR ファイルから classes.dex ファイルを除去すべきでない場合は、除去しないことを指定できます。通常、このファイルは事前最適化後に不要になるため削除されます。サードパーティ APK 署名を有効なまま残すには、この nostripping オプションを指定する必要があります。

  • PRODUCT_DEX_PREOPT_BOOT_FLAGS
  • ブートイメージをコンパイルする方法を制御するオプションを dex2oat に渡します。これにより、カスタマイズ済みイメージクラス リスト、コンパイル済みクラスリスト、コンパイラ フィルタを指定できます。

  • PRODUCT_DEX_PREOPT_DEFAULT_FLAGS
  • ブートイメージ以外のすべてをコンパイルする方法を制御するオプションを dex2oat に渡します。

  • PRODUCT_DEX_PREOPT_MODULE_CONFIGS
  • 特定のモジュールとプロダクト構成を対象とする dex2oat オプションを渡す機能を提供します。これは、プロダクトの device.mk ファイルで $(call add-product-dex-preopt-module-config,<modules>,<option>) により設定されます。<modules> は、JAR ファイルでは LOCAL_MODULE、APK ファイルでは LOCAL_PACKAGE の名前のリストです。

  • PRODUCT_DEXPREOPT_SPEED_APPS (New in Android 8)
  • プロダクトのコアとして識別され、speed コンパイラ フィルタでコンパイルすることが望ましいアプリのリスト。たとえば、SystemUI などの永続アプリがプロファイル ガイド付きコンパイルを使用できるのは次回のリブート時に限られます。したがって、プロダクトではそのようなアプリが常に AOT コンパイルされるようにする方が適切な場合があります。

  • PRODUCT_SYSTEM_SERVER_APPS (New in Android 8)
  • システム サーバーによって読み込まれるアプリのリスト。デフォルトでは、これらのアプリは speed コンパイラ フィルタでコンパイルされます。

  • PRODUCT_ART_TARGET_INCLUDE_DEBUG_BUILD(Post Android 8)
  • ART のデバッグ バージョンをデバイス上に配置するかどうか。デフォルトでは、userdebug および eng ビルドに対して有効になっています。この動作は、オプションを true または false に明示的に設定することでオーバーライドできます。

    デフォルトでは、デバイスは非デバッグ バージョン(libart.so)を使用します。デバッグ バージョンに切り替えるには、システム プロパティ persist.sys.dalvik.vm.lib.2libartd.so に設定します。

  • WITH_DEXPREOPT_PIC (Removed in Android 8)
  • Android 5.1.0 から Android 6.0.1 までのリリースの場合、WITH_DEXPREOPT_PIC を指定することで、位置独立コード(PIC)を有効化できます。これにより、イメージからコンパイルされたコードを /system から/data/dalvik-cache に再配置する必要がなくなり、データ パーティションの容量を節約できます。ただし、位置依存コードを利用する最適化が無効化されるため、実行時の影響がわずかにあります。一般的に、/data 内の容量の節約が求められるデバイスでは、PIC コンパイルを有効にしてください。

    Android 7.0 で、PIC コンパイルはデフォルトで有効化されるようになりました。

  • WITH_DEXPREOPT_BOOT_IMG_ONLY(Android 8 MR1 で削除)
  • このオプションは、WITH_DEXPREOPT_BOOT_IMG_AND_SYSTEM_SERVER_ONLY(システム サーバー JAR の事前最適化も行います)に置き換えられました。

  • PRODUCT_SYSTEM_SERVER_COMPILER_FILTER
  • このオプションは、システム サーバーのコンパイラ フィルタを指定します。

    • (Android 14(AOSP 試験運用版)以降)指定していない場合、speed-profile コンパイラ フィルタが使用されます。プロファイルが指定されていない場合は、speed コンパイラ フィルタが使用されます。
    • (Android 13 まで)指定していない場合、speed コンパイラ フィルタが使用されます。
    • speed に設定すると、speed コンパイラ フィルタが使用されます。
    • speed-profile に設定すると、speed-profile コンパイラ フィルタが使用されます。プロファイルが指定されていない場合は、verify コンパイラ フィルタが使用されます。
    • verify に設定すると、verify コンパイラ フィルタが使用されます。

  • PRODUCT_SYSTEM_SERVER_JARSPRODUCT_APEX_SYSTEM_SERVER_JARSPRODUCT_STANDALONE_SYSTEM_SERVER_JARSPRODUCT_APEX_STANDALONE_SYSTEM_SERVER_JARS
  • 以下は、システム サーバーによって読み込まれる JAR のリストです。JAR は、PRODUCT_SYSTEM_SERVER_COMPILER_FILTER で指定されたコンパイラ フィルタでコンパイルされます。

    • (必須)PRODUCT_SYSTEM_SERVER_JARS: プラットフォーム上のシステム サーバー クラスパス JAR のリスト(SYSTEMSERVERCLASSPATH の一部)。システム サーバー クラスパス JAR をこのリストに追加する必要があります。リストにシステム サーバー クラスパス JAR を追加しないと、それらの JAR が読み込まれなくなります。
    • (必須)PRODUCT_APEX_SYSTEM_SERVER_JARS: APEX を介して配信されたシステム サーバー クラスパス JAR のリスト(SYSTEMSERVERCLASSPATH の一部)。形式は <apex name>:<jar name> です。APEX システム サーバー クラスパス JAR をこのリストに追加する必要があります。このリストに APEX システム サーバー クラスパス JAR を追加しないと、それらの JAR が読み込まれなくなります。
    • (省略可、Android 13 以降)PRODUCT_STANDALONE_SYSTEM_SERVER_JARS: システム サーバーが個別のクラスローダーを使用して動的に読み込む JAR のリスト(SystemServiceManager.startServiceFromJar を使用)。このリストへのスタンドアロン システム サーバー JAR の追加は必須ではありませんが、JAR がコンパイルされ、ランタイム パフォーマンスが良好になるため、強く推奨されます。
    • (必須、Android 13 以降)PRODUCT_APEX_STANDALONE_SYSTEM_SERVER_JARS: システム サーバーが個別のクラスローダーを使用して動的に読み込む、APEX を介して配信される JAR のリスト(SystemServiceManager.startServiceFromJar を使用するか、<apex-system-service> として宣言)。形式は <apex name>:<jar name> です。スタンドアロン APEX システム サーバー JAR をこのリストに追加する必要があります。このリストにスタンドアロン APEX システム サーバー JAR を追加しないと、起動エラーが発生します。

    ブート クラスパス構成

    • プリロード済みクラスリスト
    • プリロード済みクラスリストは、起動時に zygote が初期化するクラスのリストです。これにより、各アプリでクラス初期化子を個別に実行する必要がなくなり、初期化子の起動の高速化とメモリ内でのページの共有が可能になります。プリロード済みクラスリスト ファイルは、デフォルトでは frameworks/base/config/preloaded-classes にあり、一般的なスマートフォンで使用できるようにチューニングされたリストを含んでいます。ウェアラブル デバイスなどの他のデバイスではこれと異なる場合があり、それに応じてチューニングする必要があります。あまりにも多くのクラスを追加すると、使用されないクラスを読み込む際にメモリが浪費されるため、慎重にチューニングする必要があります。追加するクラスが少なすぎると、各アプリがそれ自身のコピーを持つことが必要になり、この場合もメモリが浪費されます。

      使用例(プロダクトの device.mk 内):

      PRODUCT_COPY_FILES += <filename>:system/etc/preloaded-classes
      

      注: この行は、build/target/product/base.mk からデフォルト メイクファイルを取得するプロダクト構成メイクファイルを継承する前に配置する必要があります。

    実行時構成

    JIT のオプション

    以下のオプションは、ART JIT コンパイラが利用できる場合に限り、Android リリースに影響します。

    • dalvik.vm.usejit: JIT を有効にするかどうか。
    • dalvik.vm.jitinitialsize(デフォルトは 64K): コード キャッシュの初期容量。コード キャッシュは定期的に GC が行われ、必要に応じて増加します。
    • dalvik.vm.jitmaxsize(デフォルトは 64M): コード キャッシュの最大容量。
    • dalvik.vm.jitthreshold(デフォルトは 10000): メソッドを JIT コンパイルするためにメソッドの「ホットネス」カウンタが渡さなければならないしきい値。「ホットネス」カウンタはランタイム内部の指標です。呼び出しの数や後方ブランチなどの要素を含みます。
    • dalvik.vm.usejitprofiles: JIT プロファイルが有効になっているかどうか。このオプションは dalvik.vm.usejit が false であっても使用できます。false の場合、コンパイラ フィルタ speed-profile はメソッドを AOT コンパイルせず、verify と同じになります。
    • dalvik.vm.jitprithreadweight(デフォルトは dalvik.vm.jitthreshold / 20): アプリの UI スレッドの JIT「サンプル」の重み付け(jitthreshold を参照)。アプリを操作する際のユーザー エクスペリエンスに直接影響するメソッドのコンパイルを高速化するために使用します。
    • dalvik.vm.jittransitionweight(デフォルトは dalvik.vm.jitthreshold / 10): コンパイル コードとインタープリタ間を遷移するメソッド呼び出しの重み付け。高コストの遷移を最小限に抑えるため、関係するメソッドだけをコンパイルすることができます。

    パッケージ マネージャーのオプション

    Android 7.0 以降では、さまざまな段階で発生したコンパイル / 検証のレベルを指定する汎用的な方法があります。 コンパイル レベルは、次のデフォルト値を持つシステム プロパティで構成できます。

    • pm.dexopt.install=speed-profile
    • Google Play からアプリをインストールする際に使用されるコンパイル フィルタです。dex メタデータ ファイルで指定されたプロファイルを使用できるようにするには、インストール フィルタを speed-profile に設定することをおすすめします。プロファイルが指定されていない場合や空の場合は、speed-profile は verify と同じになります。

    • pm.dexopt.bg-dexopt=speed-profile
    • デバイスがアイドル状態、充電中、完全に充電された状態の場合に使用されるコンパイル フィルタです。プロファイル ガイド付きコンパイルを利用してストレージの容量を節約するには、speed-profile コンパイラ フィルタをお試しください。

    • pm.dexopt.boot-after-ota=verify
    • 無線(OTA)アップデート後に使用されるコンパイル フィルタ。起動に非常に長い時間がかかる事態を避けるため、このオプションで verify コンパイラ フィルタを指定することを強くおすすめします。

    • pm.dexopt.first-boot=verify
    • デバイスの初回起動時に使用されるコンパイル フィルタ。 ここで使用されるフィルタは、工場出荷後の初回の起動時間にのみ影響します。ユーザーが初めてスマートフォンを使用する際の起動時間が長くなるのを避けるには、verify フィルタの指定をおすすめします。なお、システム イメージ内のすべてのアプリが、適切なクラスローダーのコンテキストで verifyspeed-profile、または speed ですでにコンパイルされている場合、pm.dexopt.first-boot は効果を持ちません。

    dex2oat オプション

    上記のオプションのほとんどは事前最適化にのみ影響しますが、以下のオプションは事前最適化だけでなくデバイス上のコンパイルの際にも dex2oat に影響します。

    ブートイメージをコンパイルする際に dex2oat を制御するオプション:

    • dalvik.vm.image-dex2oat-Xms: 初期ヒープサイズ
    • dalvik.vm.image-dex2oat-Xmx: 最大ヒープサイズ
    • dalvik.vm.image-dex2oat-filter: コンパイラ フィルタのオプション
    • dalvik.vm.image-dex2oat-threads: 使用するスレッドの数

    ブートイメージ以外のすべてをコンパイルする際に dex2oat を制御するオプション:

    • dalvik.vm.dex2oat-Xms: 初期ヒープサイズ
    • dalvik.vm.dex2oat-Xmx: 最大ヒープサイズ
    • dalvik.vm.dex2oat-filter: コンパイラ フィルタのオプション

    Android 6.0 までのリリースについては、ブートイメージ以外のすべてをコンパイルする際の追加オプションが 1 つ用されています。

    • dalvik.vm.dex2oat-threads: 使用するスレッドの数

    Android 6.1 以降では、ブートイメージ以外のすべてをコンパイルする際の追加オプションが 2 つ用意されています。

    • dalvik.vm.boot-dex2oat-threads: 起動時に使用するスレッドの数
    • dalvik.vm.dex2oat-threads: 起動後に使用するスレッドの数

    Android 7.1 以降では、ブートイメージ以外のすべてをコンパイルする際のメモリの使用方法を制御するオプションが 2 つ用意されています。

    • dalvik.vm.dex2oat-very-large: AOT コンパイルを無効化する最小合計 dex ファイルサイズ(バイト単位)
    • dalvik.vm.dex2oat-swap: dex2oat スワップ ファイルを使用(低メモリデバイス向け)

    dex2oat の初期ヒープサイズと最大ヒープサイズを制御するオプションには、小さい値を指定しないでください。コンパイルできるアプリが制限される可能性があります。

    Android 11 以降では、コンパイラ スレッドを特定の CPU グループに制限できる 3 つの CPU アフィニティ オプションが用意されています。

    • dalvik.vm.boot-dex2oat-cpu-set: 起動時に dex2oat スレッドを実行する CPU
    • dalvik.vm.image-dex2oat-cpu-set: ブートイメージのコンパイル中に dex2oat を実行する CPU
    • dalvik.vm.dex2oat-cpu-set: ブート後に dex2oat スレッドを実行する CPU

    対象となる CPU は、カンマ区切りの CPU ID リストで指定します。たとえば、CPU 0~3 で dex2oat を実行する場合は、次のように設定します。

    dalvik.vm.dex2oat-cpu-set=0,1,2,3
    

    CPU アフィニティ プロパティを設定する場合、不要なメモリ競合や I/O 競合を避けるため、選択した CPU 数に一致するように、dex2oat スレッド数に対応するプロパティをマッチングすることをおすすめします。

    dalvik.vm.dex2oat-cpu-set=0,1,2,3
    dalvik.vm.dex2oat-threads=4
    

    Android 12 以降、次のオプションが追加されました。

    • dalvik.vm.ps-min-first-save-ms: ランタイムがアプリケーションのプロファイルを生成するのを待機する時間(アプリケーションの初回起動時)
    • dalvik.vm.ps-min-save-period-ms: アプリのプロファイルを更新するまでの最小待機時間
    • dalvik.vm.systemservercompilerfilter: システム サーバーを再コンパイルする際にデバイスが使用するコンパイラ フィルタ

    A/B 固有の構成

    ROM の構成

    Android 7.0 以降では、デバイスで 2 つのシステム パーティションを使用して A/B システム アップデートを有効にできます。システム パーティション サイズを節約するため、使用していない第 2 のシステム パーティションに事前最適化済みファイルをインストールできます。それらのファイルは、初回起動時にデータ パーティションにコピーされます。

    使用例(device-common.mk 内):

    PRODUCT_PACKAGES += \
         cppreopts.sh
    PRODUCT_PROPERTY_OVERRIDES += \
         ro.cp_system_other_odex=1
    

    デバイスの BoardConfig.mk 内:

    BOARD_USES_SYSTEM_OTHER_ODEX := true
    

    ブート クラスパス コード、システム サーバーコード、プロダクト固有のコアアプリは常にシステム パーティションにコンパイルされます。デフォルトでは、他のすべてのアプリは、使用されていない第 2 のシステム パーティションにコンパイルされます。これは SYSTEM_OTHER_ODEX_FILTER で制御できます。そのデフォルト値は次のとおりです。

    SYSTEM_OTHER_ODEX_FILTER ?= app/% priv-app/%
    

    バックグラウンド dexopt OTA

    A/B 対応デバイスでは、アプリをバックグラウンドでコンパイルして新しいシステム イメージにアップデートできます。オプションとして、コンパイル スクリプトおよびバイナリをシステム イメージに組み込むことができます。バックグラウンドでのアプリのコンパイルをご覧ください。このコンパイルに使用されるコンパイル フィルタは、次のように制御されます。

    pm.dexopt.ab-ota=speed-profile
    

    プロファイル ガイド付きコンパイルを利用してストレージの容量を節約するため、speed-profile を使用することをおすすめします。