Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Androidバイトコード実行環境 の歴史をサクッと振り返る

Androidバイトコード実行環境 の歴史をサクッと振り返る

Androidバイトコード実行環境の歴史をサクッと振り返る
2021/03/26 potatotipsでの登壇資料
https://potatotips.connpass.com/event/202810/

nichiyoshi

March 26, 2021
Tweet

More Decks by nichiyoshi

Other Decks in Programming

Transcript

  1. Androidバイトコード実行環境
    の歴史をサクッと振り返る
    ただのインタプリタからハイブリッドコンパイル方式に至るまで
    をざっくり理解する

    View Slide

  2. 自己紹介
    ● 名前:Nichika Yoshida @nichiyoshi
    ● 所属:FiNC Technologies
    ● 職種:Androidエンジニア 兼 スクラムマスター

    View Slide

  3. 唯一の特徴...

    View Slide

  4. 最初に期待値調整
    ● 以下の話はしません
    ○ 最新の知見
    ○ 実装的な話
    ○ アフリカあるある

    View Slide

  5. 今日話すこと
    ● Android初期 ~ 現在までの、バイトコード実行環境周辺の変遷
    ○ なんの課題を解決するために、どんなことをしたのか

    View Slide

  6. 今日のゴール
    ● Androidバイトコード実行環境の変遷についてざっくり理解する
    ● 現時点でのARTのフローをざっくり理解する

    View Slide

  7. 今日話さないこと
    ● バイトコード実行環境ってなんぞや
    ● Dalvikバイトコードやdexファイルってなんぞや
    ● Zygoteを使ったプロセス間のメモリ共有 (補足に入れます)
    ● mmap , clean/dirtyなメモリ (補足に入れます)
    などなど
    社内LTで12分かかったので、かなり駆け足で進むと思います
    補足資料もあるので興味ある方はあとで読んでください

    View Slide

  8. スキップ予定:dexファイルとDalvik VM
    ● apkとdexファイル
    ○ Java/KotlinのコードをJavaバイトコード(.class)に変換
    ○ .classをDalvikバイトコードに変換し、 dexファイル(.dex)にひとまとめ
    ○ dexファイルやリソースなどをまとめて apkにしてGoogle Playにup
    ● このDalvikバイトコードを実行する環境がDalvik VM
    ○ JVM同様、メモリ配置、ガベッジコレクションなども兼ね備える
    .java .class
    .kt .class
    .kt .class
    .class classes.dex
    javac/kotlinc
    APK
    classes.dex
    Resource

    View Slide

  9. スキップ予定:dexとDalvik VMの利点
    ● dexファイルの利点
    ○ 複数の.classで共通している文字列 (どのクラスでも使うimport宣言など)を重複管理せず共有する
    ことでファイルサイズをかなり小さく することができる
    ● Dalvik VMの利点
    ○ JVMはスタック型仮装マシンで、 Dalvik VMはレジスタ型仮想マシン
    ■ レジスタ型マシンの方がインタプリタでの 実行速度が速く、生成されるバイナリが小さい
    ● dexファイルとDalvik VMは、ストレージやメモリに制限があり、安定してサクサク動
    くことが重要なAndroidアプリに適している

    View Slide

  10. スキップ予定:クラスファイルとdexファイルに関する話をもうちょい
    ● classファイルよりdexファイルの方がバイトコードがコンパクトだし可読性が良い
    ○ ファイルサイズの違い:dexファイルは複数のクラスを一つのバイナリファイルにまとめる
    ことができ、複数ファイ
    ルで共通して記述されている文字列
    (パッケージ名、クラス名、型名、メソッド名など
    )を共通化してidとして間接
    参照できるようにすることで、同じ文字列の重複を防ぎ、
    ファイルサイズをかなり小さくできる

    ● dexは再配置なしでメモリにmmapして実行できる
    ○ メモリ上にそのファイルがあるように見えるが、実際にはファイルにアクセスされるまでメモリにはロードしない。
    アクセスされるまでメモリロードしないのでメモリ節約できる。
    Linuxが、不要な時には破棄してくれるし、再度ア
    クセスしたら自動で読み込んでくれる

    ● dexは無圧縮
    ○ 圧縮しているとメモリ上で解凍が必要になるし、
    dirtyなのでmmapできず、Linuxによるメモリ自動破棄ができな
    くなる
    ● dexにはメソッドIDの64K問題(id制限が0xffffで65536通り, 64*2^10通り)がある =>
    multi-dexで解決 (classes1.dex, classes2.dex, ….)

    View Slide

  11. スキップ予定: なんでそんなにメモリにシビアなの
    ● Android初期はめっちゃメモリ小さかったし、今も限界がある
    ● SDカードなどAndroidで使われる二次メモリは書き込み制限があるのでスワップができないようになって
    いて、メモリ情報のディスクへの一時退避ができない

    View Slide

  12. スキップ予定: メモリ節約の工夫
    ● なるべく多くのメモリをアプリ同士で共有する
    ○ Androidでは、アプリのプロセスは Zygoteというプロセスをforkする。Zygote プロセスは、システム
    起動時に開始され、共通のフレームワークのコードとリソース(アクティビティ テーマなど)を読み込
    む。新しいプロセスを開始するときは、システムが Zygote プロセスを fork してから、新しいプロセ
    スでアプリのコードをロードして実行する。 この方法により、フレームワークのコードとリソースに割
    り当てられた RAM ページのほとんどを、すべてのアプリプロセスで共有 できる。
    ○ 都度プロセスを起動して ARTを初期化してクラスライブラリを初期化して ...のような処理が不要にな
    るので起動時間も早くなる
    ● なるべく多くのメモリを、mmapできるCleanな状態に保つ
    ○ 通常のVMだと、バイナリをメモリ上に読み込んでアドレス解決などして実行する => バイナリとメモ
    リ上のデータが一致しない => Dirtyなメモリ
    ○ Androidでは、実行バイナリを mmapというLinuxのAPIを用いてそのまま使おうとする => Cleanなメ
    モリ => Linuxが、不要な時には破棄してくれるし、再度アクセスしたら自動で読み込んでくれる 。ア
    クセスされるまでメモリロードしないのでメモリ節約できる。

    View Slide

  13. とりあえず前提でこれだけ知っといて
    ● Androidでは、JavaバイトコードでなくてDalvikバイトコードを動かすよ
    ● 実行環境はJVMじゃなくて、ART(旧Dalvik VM)っていうAndroid用の実行環境だよ

    View Slide

  14. こっからようやく本題

    View Slide

  15. Android初期~2.1 | Dalvik VM
    ● Dalvik VMがDalvikバイトコードを逐次解釈で実行していく素朴なインタプリタ
    ● 課題:逐次実行なのでCPU負荷が高いような処理が遅くなりがちだった
    app
    app execution
    interpret
    input to
    補足:初期のAndroidはメモリが今以上に少なく、
    JITコンパイルなどをしてバイナリコードを生成するとメモリを逼迫してしまう。ちょっとでもメモリを節約
    するために純粋なインタプリタにしたらしい。

    View Slide

  16. Android 2.2~4.4 | Dalvik VM + JIT
    ● インタープリタで実行していく過程で、特にパフォーマンスに影響しそうなすごく重要
    なコードのみを最低限JIT (Just In Time)でコンパイルし、次に同じ処理が呼ばれた
    時にはこのバイナリをCPUが直接実行することで、CPU負荷が高いような処理の
    実行速度の高速化
    ● 課題:アプリ実行中に一瞬JITが走りカクついてパフォーマンス低下
    app
    app execution
    interpret/JIT
    input to
    補足:JITで生成されたバイナリは
    mmapできなくてメモリ効率が悪いので、あくまで一部に限定。あとはバッテリー消費にも影響与える

    View Slide

  17. Android5.0 ~ 6.x | Android RunTime(ART) + AOTコンパイル
    ● アプリのインストール時にバイトコードを全部まとめてバイナリにコンパイル
    ● アプリ起動時にはバイナリをCPUが直接実行するので高速
    ● 課題:システムアップデートの都度、全てのアプリをAOTコンパイルするので、シス
    テムアップデートにめちゃくちゃ時間かかる、30分とか。
    補足:他にも、アプリ起動中にバックグラウンドで他のアプリを更新中にパフォーマンス下がったり、あんま使ってないアプリやコードもバイナリ化さ
    れてメモリが無駄になったりする
    app app execution
    input to
    install & AOTコンパイル

    View Slide

  18. View Slide

  19. Android7.0(N)~ | ART + JIT + profile guidedコンパイル
    ● タイミングを分けて部分的にバイナリにコンパイル
    ○ アプリ起動&実行中にJITで重要な部分のみバイナリ化
    ○ JITの時によく実行されるメソッドや使われるライブラリをプロファイル し、プロファイル結果で重要な
    部分のみを、端末が充電中かつアイドル時に、 1日1回のみバイナリ化(Profile Guided コンパイル)
    ● 各ユーザーのアプリ利用に合わせて最適化できる

    View Slide

  20. Android8.0(O)
    ● 同時圧縮ガベージ コレクタ
    ○ Android 7.0 と比較して、ヒープサイズは平均で
    32% 小さく
    ● Dexlayout
    ○ まとめてアクセスされることが多い
    dex ファイルの構成要素をグループ化することで、プログラムの局所性を改善してメモリアクセス
    パターンを効率化し、
    RAM の節約と起動時間の短縮を実現
    ● など様々な改善があるが、JIT + Profile Guided Compileの仕組みは変わらず

    View Slide

  21. Android9.0(P)~ | ART + AOT +JIT + profile guidedコンパイル
    ● Cloud プロファイル
    ○ JITで作成されたProfileデータが、クラウドにアップロード される
    ○ 様々なユーザーのProfileを集約・解析し、何度も使われているコードは AOTコンパイルされる

    View Slide

  22. ARTの全体の流れ
    アプリ実行

    View Slide

  23. ARTの全体の流れ
    Dalvikバイトコードをインタープリタ
    が逐次実行しながら、
    重要な箇所はJITコンパイルしてバ
    イナリをキャッシュし、次回は高速に
    実行

    View Slide

  24. ARTの全体の流れ
    アプリ実行中、よく使われる処理は
    プロファイルに保存
    Android9(P)以降だとプロファイルは
    クラウドにもアップロードされる

    View Slide

  25. ARTの全体の流れ
    アプリが充電中かつアイドルの時
    に、プロファイル結果に基づいてよく
    使われるコードをバイナリにコンパイ

    View Slide

  26. ARTの全体の流れ
    元のバイトコードの一
    部をコンパイルされた
    コードでreplace

    View Slide

  27. まとめ
    ● Androidのバイトコード開発環境は、メモリや実行速度の戦いで常に進
    化してきた
    ● 今の形式:ART + AOT +JIT + profile guidedコンパイル

    View Slide

  28. 今日のゴールは達成できましたか?
    ● Androidバイトコード実行環境の変遷についてざっくり理解する
    ● 現時点でのARTのフローをざっくり理解する
    https://source.android.com/devices/tech/dalvik/jit-compiler

    View Slide

  29. 参考資料
    ● 記事
    ○ ART ジャストインタイム(JIT)コンパイラの実装
    ○ クラウド ART 最適化プロファイルによるアプリのパフォーマンス改善
    ○ バージョンごとのARTに関する箇所
    ■ Android7 プロファイルに基づいた JIT / AOT コンパイル
    ■ Android8 ART の改善点
    ■ Android9 ART での DEX ファイルの Ahead-of-time 変換
    ■ Android10 ART の最適化
    ● YOUTUBE
    ○ The Evolution of ART - Google I/O 2016
    ○ LAS16-201: ART JIT Android N
    ● BOOK
    ○ Androidを支える技術〈Ⅰ〉──60fpsを達成するモダンな GUIシステム

    View Slide

  30. View Slide