🙌

Androidアプリのコンパイルについて

2024/06/19に公開

自分用にメモしたものですが、質問/ご意見/修正案など、何かあればご連絡ください🙇

Androidコンパイル/インストールの変遷

Dalvik(JIT)-> ART -> ART with Profile Compile -> added Cloud Profile

バージョン間のコンパイル動作まとめ

開発者側でのコンパイル

Java/Kotlinのソースコードは .classというバイトコードにコンパイルされる。

ART

  • Androidアプリの実行環境を提供する。各端末に搭載されている
  • アプリごとに持つ部分と、Systemが持ち、アプリ間で共有して利用する部分とに分かれる

In Android, the ART runtime is split into two parts:
The system-level ART code: This includes the core ART libraries, runtime components, and virtual machine implementation. This part of the code is shared among all app processes and is loaded into memory by the Zygote process.
The app-level ART instance: Each app process has its own instance of the ART virtual machine, but this instance does not contain a complete copy of the ART code. Instead, it has a reference to the shared system-level ART code and uses it for execution. 参照

アプリはバイトコードの状態で配布される。(.dex)
ARTが、アプリインストール時のみ、バイトコードを機械語に変換する
(実行時に毎回ではなく、Ahead of time AOTコンパイルということ)

ただし、下記の課題がある。

  • 機械語の分も保存しておかなければならない(ストレージ消費)
  • 起動時にディスクから取り出してキャッシュを構成するので起動時間がかかる

この問題のため下記の「プロファイルによる最適化」が導入された

Profile-guided コンパイル

JITコンパイルベースで実行時にバイトコード機械語変換。
(アプリの実行のたびに機械語への変換が行われる。)

ユーザーがアプリのどの部分を多く使っているか学習し、
そこの部分を起動時にコンパイル(JIT機械語変換)し、キャッシュする。

これによって、ART で課題だったディスクスペースと起動時間の問題を解消できる。

ただし、このままでは、学習するまで改善できない、という問題がある。
解決の手段が下記。

Cloud ProfilesとBaseline Profiles

Cloud Profile : Android 9より導入されたART最適化。
Baseline Profile : Android 7より導入された。

ベースライン プロファイルでアプリのパフォーマンスを改善

https://android-developers.googleblog.com/2019/04/improving-app-performance-with-art.html
ベースライン プロファイルを使用すると、含まれるコードパスに対して解釈とジャストインタイム(JIT)コンパイルの手順を行う必要がなくなるため、初回起動からのコード実行速度が約 30% 向上します。

ベースライン プロファイルを使用しない場合、すべてのアプリコードは解釈後にメモリ内で JIT コンパイルされるか、デバイスがアイドル状態のときにバックグラウンドで odex ファイルに書き込まれます。 アプリをインストールまたは更新した後、初回の実行時から新しいコードパスが最適化されるまで、ユーザーは最適なパフォーマンスが得られません。多くのアプリで、最適化後にパフォーマンスが約 30% 向上することがわかっています。
(後述のローカルプロファイルを作る部分と同じ。「解釈後にメモリ内で JIT コンパイル」=> インタプリタで実行され、利用頻度が高いメソッドをJITコンパイルされ、プロファイルされる。)

クラウドプロファイル/ベースラインプロファイル共に、インストール時のコンパイル用に配布される。
さらに、ART は、アプリ使用時に他のプロファイル ルールを追加し、デバイスがアイドル状態のときにそれらをコンパイルすることで、ベースライン プロファイルの内容をさらに改善できます。

ベースラインプロファイルの概要と導入

ARTコンパイルの仕組みより引用:

ART では、事前(AOT)コンパイルを使用し、Android 7 以降では AOT コンパイル、ジャストインタイム(JIT)コンパイル、インタプリタを組み合わせて使用します。
Google Pixel デバイスの場合は、以下のフローで動作するように構成されています。

アプリは最初に、Google Play ストアから配信されるメタデータ(.dm)ファイルとともにインストールされます。このファイルには、クラウド プロファイルが含まれています。このクラウド プロファイルに記載されているメソッドが AOT コンパイルされます。 アプリが dex メタデータ ファイルなしでインストールされている場合、AOT コンパイルは行われません。

最初の数回の実行では、AOT コンパイルされていないメソッドは、インタプリタで実行されます。インタプリタで実行されたメソッドのうち、実行される頻度の高いメソッドが JIT コンパイルされます。実行に基づいてローカル プロファイルが生成され、クラウド プロファイルがあれば、それと結合されます。 (← おそらくベースラインプロファイルが提供されていない場合)

デバイスがアイドル状態で充電中のときに、コンパイル デーモンが実行され、最初の数回の実行時に生成され、結合されたプロファイルに基づいてアプリが再度コンパイルされます。

このコンパイル デーモンで生成されたアーティファクトは、その後のアプリの実行で使用されます。このアーティファクトには、生成済みのコードよりも AOT コンパイルが進んだコードが含まれます。
AOT コンパイルされていないコードは、インタプリタで実行されるか、JIT コンパイルされます。この実行に基づいて、プロファイルのインストール状態が更新されます。その後のコンパイル デーモンの実行では、このプロファイルが選択されます。

Discussion