GraalVMダッシュボードを使用したネイティブ実行可能ファイルのサイズの最適化

GraalVMダッシュボードは、ネイティブ実行可能ファイルの構成を視覚化するWebベースのツールです。ネイティブ実行可能ファイルに含まれるパッケージ、クラス、およびメソッドの内訳を表示し、そのヒープ・サイズに最も影響を与えているオブジェクトのサマリーを視覚的に提供します。GraalVMダッシュボードでは、ネイティブ・イメージ・ビルダーによって作成されたレポート・ファイルが使用されます。(詳細は、GraalVMのスタート・ガイドを参照してください。)

このガイドでは、ダッシュボードを使用してネイティブ実行可能ファイルのサイズを最適化する方法を示します。従来のfortune Unixプログラムをシミュレートする"fortune"サンプル・アプリケーションの2つの実装が導入されています(詳細は、fortuneを参照してください)。

ノート: このガイドでは、Mavenがインストールされていることを前提としています。

Fortune

最初の実装(fortune)の内容をネイティブ実行可能ファイルとしてパッケージ化し、その構成を確認します。

  1. GraalVM JDKがインストール済であることを確認します。最も簡単に始めるには、SDKMAN!を使用します。その他のインストール・オプションについては、「ダウンロード」セクションを参照してください。

  2. リポジトリをダウンロードまたはクローニングし、fortune-demo/fortuneディレクトリに移動します:
     git clone https://github.com/graalvm/graalvm-demos
    
     cd fortune-demo/fortune-maven
    
  3. プロジェクトをビルドします:
     mvn clean package
    
  4. ビルドが成功したら、トレース・エージェントを使用してJVMでアプリケーションを実行します。GraalVMをインストールしたため、GraalVM JDKで実行されます。
     mvn -Pnative -Dagent exec:exec@java-agent
    

    アプリケーションはランダムなメッセージを返します。エージェントは、target/native/agent-outputサブディレクトリに構成ファイルを生成します。

  5. GraalVMネイティブ・イメージおよびMavenを使用して、このアプリケーションのネイティブ実行可能ファイルをビルドします:
     mvn -Pnative -Dagent package
    

    コマンドが完了すると、ネイティブ実行可能ファイルfortuneがプロジェクトの/targetディレクトリに生成され、使用できるようになります。

  6. ネイティブ実行可能ファイルを直接起動してアプリケーションを実行します:
     ./target/fortune
    

    アプリケーションはランダムなフレーズをゆっくりと出力します。

    アプリケーションのpom.xmlファイルは、ネイティブ・イメージMavenプラグインを使用してネイティブ実行可能ファイルをビルドします。次の2つのオプションを使用して診断データを生成するように構成されます:

     -H:DashboardDump=fortune -H:+DashboardAll
    

    これらのオプションにより、fortune.bgvという名前のファイルが生成されます。(様々なオプションの詳細は、GraalVMダッシュボードのデータのダンプに関する項を参照してください。)

    JARファイルとネイティブ実行可能ファイルのサイズを比較します(duの使用など):

     du -sh target/*
     0B	    target/archive-tmp
     136K	target/classes
     17M     target/fortune
     2.0M	target/fortune-1.0-jar-with-dependencies.jar
     32K	    target/fortune-1.0.jar
     44M	    target/fortune.bgv
     4.0K	target/fortune.build_artifacts.txt
     0B	    target/generated-sources
     4.0K	target/maven-archiver
     8.0K	target/maven-status
     0B	    target/test-classes
    

    ネイティブ実行可能ファイルのサイズが17MBであるのに対し、JARファイルのサイズは2MBです。サイズが増加するのは、ネイティブ実行可能ファイルに必要なすべてのランタイム・コードと事前に初期化されたデータがヒープに含まれているためです。

  7. GraalVMダッシュボードを開き、fortune.bgvファイルをロードします。(「+」をクリックし、「ファイルの選択」をクリックして、targetディレクトリからfortune.bgvファイルを選択し、「OK」をクリックします。)

    GraalVMダッシュボードには、ネイティブ実行可能ファイルを視覚化したものが2つ(コード・サイズの内訳とヒープ・サイズの内訳)表示されます。(詳細は、コード・サイズの内訳に関する項およびヒープ・サイズの内訳に関する項をそれぞれ参照してください。)

    コード・サイズの内訳ビュー

    上のスクリーンショットは、fortuneネイティブ実行可能ファイルのコード内訳を視覚化したもので、その大部分は、パッケージcom.fasterxmlに実装されているJackson JSONパーサー・ライブラリで構成されています。ネイティブ実行可能ファイルのサイズを減らす方法の1つは、コードが占める容量を最小限に抑えることです。コード・サイズの内訳によって、ネイティブ実行可能ファイルに含まれるパッケージが占める容量を把握できます。

    さらに、下のスクリーンショットは、ネイティブ実行可能ファイルのヒープに4MBのバイトとほぼ800KBの文字列が含まれていることを示しています。ネイティブ実行可能ファイルのサイズを減らすもう1つの方法は、ヒープのサイズを最小化することです。

    ヒープ・サイズの内訳ビュー

    次の項では、コードの量を減らし、ヒープのサイズを小さくするfortuneアプリケーションの代替実装について検討します。

静的Fortune

fortuneアプリケーションの最初の実装では、Jackson JSONパーサー (パッケージcom.fasterxml)を実行時に使用して、ネイティブ・イメージ・ビルダーがネイティブ実行可能ファイルに含めたリソース・ファイルの内容を解析します。代替実装("staticfortune"という名前)では、ビルド時にリソース・ファイルの内容を解析します。つまり、リソース・ファイルは実行可能ファイルに含まれなくなります。ファイルの解析に必要なコードはビルド時にのみ必要となるため、ネイティブ実行可能ファイルから省略されます。

  1. プロジェクト・ディレクトリに移動し、プロジェクトをビルドします:
     cd ../staticfortune
    
     mvn clean package
    
  2. トレース・エージェントを使用して、JVM (GraalVM JDK)でアプリケーションを実行します:
     mvn -Pnative -Dagent exec:exec@java-agent
    

    アプリケーションはランダムなメッセージを出力します。エージェントは、target/native/agent-outputサブディレクトリに構成ファイルを生成します。

  3. 静的なネイティブ実行可能ファイルをビルドします:
     mvn -Pnative -Dagent package
    

    コマンドが完了すると、ネイティブ実行可能ファイルstaticfortuneがプロジェクトの/targetディレクトリに生成され、使用できるようになります。

  4. デモを実行するには、ネイティブ実行可能ファイルを直接起動するか、Mavenプロファイルを使用して起動します:
     ./target/staticfortune
    

    アプリケーションは、最初の実装とまったく同じように動作するはずです。

    アプリケーションのpom.xmlファイルは、再度ネイティブ・イメージMavenプラグインを使用してネイティブ実行可能ファイルをビルドします。ただし、この実装では、ビルド時にクラスdemo.StaticFortuneを初期化するためのオプションが追加されています:

     -H:DashboardDump=staticfortune -H:+DashboardAll --initialize-at-build-time=demo.StaticFortune
    

    JARファイルとネイティブ実行可能ファイルのサイズを比較します:

     du -sh target/*
     0B	    target/archive-tmp
     76K	    target/classes
     0B	    target/generated-sources
     4.0K	target/maven-archiver
     4.0K	target/maven-status
     4.3M	target/staticfortune
     2.0M	target/staticfortune-1.0-jar-with-dependencies.jar
     32K	    target/staticfortune-1.0.jar
     9.0M	target/staticfortune.bgv
     4.0K	target/staticfortune.build_artifacts.txt
     0B	    target/test-classes
    

    ネイティブ実行可能ファイルのサイズが17MBから4.3MBに削減されました。

    サイズが減少するのは、ネイティブ・イメージMavenプラグインで使用される--initialize-at-build-time=引数を使用したためです。

  5. ビルドにより、staticfortune.bgvという名前のファイルが作成されました。これをGraalVMダッシュボードにロードして、staticfortuneネイティブ実行可能ファイルの構成を表示します。

    コード・サイズの内訳ビュー

    上のスクリーンショットは、com.fasterxmlパッケージのコードが存在しなくなったことを示しています。また、java.utiljava.mathおよびjava.textパッケージに含まれるコードの量も削減されています。

    下のスクリーンショットは、文字列に指定されたヒープの量が大幅に削減され(767KBから184KB)、バイトも4MBから862KBに削減されたことを示しています。

    ヒープ・サイズの内訳ビュー