ネイティブ・イメージ・ビルド出力

ここでは、GraalVMネイティブ・イメージのビルド出力に関する情報を示します。HelloWorldクラスのネイティブ実行可能ファイルをビルドする際の出力例を次に示します:

================================================================================
GraalVM Native Image: Generating 'helloworld' (executable)...
================================================================================
[1/8] Initializing...                                            (2.8s @ 0.15GB)
 Java version: 20+34, vendor version: GraalVM CE 20-dev+34.1
 Graal compiler: optimization level: 2, target machine: x86-64-v3
 C compiler: gcc (linux, x86_64, 12.2.0)
 Garbage collector: Serial GC (max heap size: 80% of RAM)
[2/8] Performing analysis...  [****]                             (4.5s @ 0.54GB)
   3,175 (72.62%) of  4,372 types reachable
   3,842 (50.58%) of  7,596 fields reachable
  15,260 (45.61%) of 33,458 methods reachable
     962 types,    83 fields, and   492 methods registered for reflection
      57 types,    55 fields, and    52 methods registered for JNI access
       4 native libraries: dl, pthread, rt, z
[3/8] Building universe...                                       (0.8s @ 0.99GB)
[4/8] Parsing methods...      [*]                                (0.6s @ 0.75GB)
[5/8] Inlining methods...     [***]                              (0.3s @ 0.32GB)
[6/8] Compiling methods...    [**]                               (3.7s @ 0.60GB)
[7/8] Layouting methods...    [*]                                (0.8s @ 0.83GB)
[8/8] Creating image...       [**]                               (3.1s @ 0.58GB)
   5.32MB (24.22%) for code area:     8,702 compilation units
   7.03MB (32.02%) for image heap:   93,301 objects and 5 resources
   8.96MB (40.83%) for debug info generated in 1.0s
 659.13kB ( 2.93%) for other data
  21.96MB in total
--------------------------------------------------------------------------------
Top 10 origins of code area:            Top 10 object types in image heap:
   4.03MB java.base                        1.14MB byte[] for code metadata
 927.05kB svm.jar (Native Image)         927.31kB java.lang.String
 111.71kB java.logging                   839.68kB byte[] for general heap data
  63.38kB org.graalvm.nativeimage.base   736.91kB java.lang.Class
  47.59kB jdk.proxy1                     713.13kB byte[] for java.lang.String
  35.85kB jdk.proxy3                     272.85kB c.o.s.c.h.DynamicHubCompanion
  27.06kB jdk.internal.vm.ci             250.83kB java.util.HashMap$Node
  23.44kB org.graalvm.sdk                196.52kB java.lang.Object[]
  11.42kB jdk.proxy2                     182.77kB java.lang.String[]
   8.07kB jdk.internal.vm.compiler       154.26kB byte[] for embedded resources
   1.39kB for 2 more packages              1.38MB for 884 more object types
--------------------------------------------------------------------------------
Recommendations:
 HEAP: Set max heap for improved and more predictable memory usage.
 CPU:  Enable more CPU features with '-march=native' for improved performance.
--------------------------------------------------------------------------------
    0.8s (4.6% of total time) in 35 GCs | Peak RSS: 1.93GB | CPU load: 9.61
--------------------------------------------------------------------------------
Produced artifacts:
 /home/janedoe/helloworld/helloworld (executable)
 /home/janedoe/helloworld/helloworld.debug (debug_info)
 /home/janedoe/helloworld/sources (debug_info)
================================================================================
Finished generating 'helloworld' in 17.0s.

ビルド・ステージ

初期化

このステージでは、ネイティブ・イメージ・ビルド・プロセスが設定され、Featuresが初期化されます。

ネイティブ・イメージの種類

デフォルトでは、ネイティブ・イメージは実行可能ファイルを生成しますが、ネイティブ共有ライブラリおよび静的実行可能ファイルを生成することもできます。

Javaバージョン情報

ネイティブ・イメージ・プロセスのJavaおよびベンダーのバージョン。どちらも、生成されるネイティブ・バイナリ内のjava.vm.versionおよびjava.vendor.versionプロパティにも使用されます。イシューを作成する場合は、バージョンとベンダーを報告してください。

Graalコンパイラ

Graalコンパイラによって使用される、選択された最適化レベルとターゲットとなるマシン・タイプ。最適化レベルは-Oオプションで制御でき、デフォルトで2に設定されるため、積極的な最適化が可能になります。-Obを使用してクイック・ビルド・モードを有効にすると、コンパイル・ステージが高速になります。これは、開発時またはピーク・スループットが重要でなく、サイズを最適化する場合に便利です。ターゲット・マシン・タイプは-marchオプションで選択でき、AMD64ではx86-64-v3、AArch64ではarmv8-aにデフォルト設定されます。このオプションの使用方法に関する推奨事項は、こちらを参照してください。

Oracle GraalVMでは、プロファイルに基づく最適化(PGO)に関する情報もこの行に表示されます。

Cコンパイラ

ネイティブ・イメージ・ビルド・プロセスで使用されるCコンパイラの実行可能ファイル、ベンダー、ターゲット・アーキテクチャおよびバージョン情報。

ガベージ・コレクタ

生成された実行可能ファイル内で使用されるガベージ・コレクタ:

詳細については、メモリー管理のドキュメントを参照してください。

最大ヒープ・サイズ

デフォルトでは、ヒープ・サイズはシステム・メモリーの特定の割合に制限されるため、ガベージ・コレクタはポリシーに従ってメモリーを自由に割り当てることができます。ネイティブ実行可能ファイルを呼び出すときに-Xmxオプションを使用すると(たとえば、64MBの場合は./myapp -Xmx64m)、最大ヒープ・サイズが制限され、メモリー・フットプリントが低く、予測しやすくなります。これにより、場合によってはレイテンシが改善されることもあります。ネイティブ・イメージを使用してビルドする場合は、-R:MaxHeapSizeオプションを使用して、最大ヒープ・サイズを事前構成します。

ユーザー固有の機能

ユーザーによって提供または明確に有効化される、またはフレームワークなどによってユーザーに暗黙的に登録されるすべてのFeatures。GraalVMネイティブ・イメージは、このリストから除外される多数の内部機能をデプロイします。

分析の実行

このステージでは、ポイントツー分析が実行されます。進捗状況インジケータは、分析の反復数を視覚化します。反復数が多いと、構成ミスや誤動作機能によって生じる可能性のある分析の問題を示すことがあります。

アクセス可能なタイプ、フィールドおよびメソッド

アクセス可能なタイプ(プリミティブ、クラス、インタフェースおよび配列)、フィールドおよびメソッドの数と、ビルド・プロセスの一部としてロードされたタイプ、フィールドおよびメソッドの合計数。アクセスできないロードされた要素の数が著しく多い場合、構成に問題がある可能性があります。オーバーヘッドを削減するには、クラス・パスとモジュール・パスに、アプリケーションのビルドに必要なエントリのみが含まれていることを確認してください。

リフレクション登録

リフレッシュ用に登録されているタイプ、フィールドおよびメソッドの数。数値が大きいと、大量のリフレクション・オーバーヘッドが発生し、ビルド・プロセスが遅くなり、ネイティブ・バイナリのサイズが大きくなります(リフレクション・メタデータに関する項を参照)。

JNIアクセス登録

JNIアクセス用に登録されているタイプ、フィールドおよびメソッドの数。

実行時コンパイル済メソッド

実行時コンパイル用にマークされたメソッドの数。この数値は、Truffle言語の構築時など、実行時コンパイルが実行可能ファイルに組み込まれている場合にのみ表示されます。実行時コンパイル済メソッドは、ヒープ内のグラフ・エンコーディングを考慮します。

ユニバースの構築

このステージでは、すべてのタイプ、フィールドおよびメソッドを持つユニバースが構築され、ネイティブ・バイナリの作成に使用されます。

メソッドの解析

このステージでは、Graalコンパイラは、アクセス可能なすべてのメソッドを解析します。進捗状況インジケータは、増加する間隔で定期的に出力されます。

メソッドのインライン化

このステージでは、簡単なメソッドのインライン化が実行されます。進捗状況インジケータは、インライン化の反復数を視覚化します。

メソッドのコンパイル

このステージでは、Graalコンパイラは、アクセス可能なすべてのメソッドをマシン・コードにコンパイルします。進捗状況インジケータは、増加する間隔で定期的に出力されます。

メソッドのレイアウト

このステージでは、コンパイルされたメソッドがレイアウトされます。進捗状況インジケータは、増加する間隔で定期的に出力されます。

イメージの作成

このステージでは、ネイティブ・バイナリが作成され、ディスクに書き込まれます。デバッグ情報もこのステージの一部として生成されます(リクエストされた場合)。

コード領域

コード領域には、アクセス可能なすべてのメソッド用にGraalコンパイラによって生成されたマシン・コードが含まれます。したがって、アクセス可能なメソッドの数を減らすと、コード領域のサイズも小さくなります。

コード領域のオリジン

コード領域のマシン・コードがどこから来ているかをユーザーが理解できるように、ビルド出力には上位のオリジンの内訳が表示されます。オリジンはJavaソースのグループであり、使用可能な情報に応じて、JARファイル、パッケージ名またはクラス名です。たとえば、java.baseモジュールには、JDKのベース・クラスが含まれます。svm.jarファイル、org.graalvm.nativeimage.baseモジュールおよび同様のオリジンには、ネイティブ・イメージ・ランタイムの内部ソースが含まれます。コード領域のサイズとそれに伴うネイティブ実行可能ファイルの合計サイズを削減するには、コード領域の内訳に基づいてアプリケーションの依存関係を再評価します。一部のライブラリおよびフレームワークは他のものよりもネイティブ・イメージに対してより適切に準備され、新しいバージョンのライブラリまたはフレームワークではコード・フットプリントを改善(または悪化)できます。

イメージ・ヒープ

ヒープには、様々な目的で静的アプリケーション・データ、メタデータ、byte[]などのアクセス可能なオブジェクトが含まれています(次を参照)。

byte[]に格納される一般的なヒープ・データ

java.lang.Stringにもコード・メタデータにもリフレクション・メタデータにもグラフ・エンコーディングにも使用されないすべてのbyte[]オブジェクトの合計サイズ。したがって、アプリケーション・コードからbyte[]オブジェクトを含めることもできます。

byte[]に格納された埋込みリソース

ネイティブ・バイナリ内のリソース(Class.getResource()を介してアクセスされるファイルなど)の格納に使用されるすべてのbyte[]オブジェクトの合計サイズ。リソースの数は「ヒープ」セクションに表示されます。

byte[]に格納されるコード・メタデータ

コード領域のメタデータに使用されるすべてのbyte[]オブジェクトの合計サイズ。したがって、アクセス可能なメソッドの数を減らすと、このメタデータのサイズも小さくなります。

byte[]に格納されたリフレクション・メタデータ

タイプ、フィールド、メソッドおよびコンストラクタ・データを含む、リフレクション・メタデータに使用されるすべてのbyte[]オブジェクトの合計サイズ。リフレクション・メタデータの量を減らすには、リフレクションに登録される要素の数を減らします。

byte[]に格納されるグラフ・エンコーディング

グラフ・エンコーディングに使用されるすべてのbyte[]オブジェクトの合計サイズ。これらのエンコーディングは、実行時コンパイル済メソッドの結果です。したがって、このようなメソッドの数を減らすと、対応するグラフ・エンコーディングのサイズも小さくなります。

デバッグ情報

生成されたデバッグ情報の合計サイズ(有効な場合)。

その他のデータ

コード領域にもヒープにもデバッグ情報にもないバイナリ内のデータの量。通常、このデータにはネイティブ・イメージの内部情報が含まれているため、先頭にしないでください。

推奨事項

ビルド出力には、ネイティブ・イメージを最大限に活用するのに役立つ次の推奨事項が1つ以上含まれている場合があります。

AWT: Abstract Window Toolkitの到達可能性メタデータがありません

ネイティブ・イメージ分析には、java.awtパッケージのクラスが含まれていますが、到達可能性メタデータが見つかりませんでした。トレース・エージェントを使用して、アプリケーションのそのようなメタデータを収集します。そうしないと、アプリケーションが正しく動作しない可能性があります。アプリケーションがデスクトップ・アプリケーションではない場合(SwingやAWTを直接使用する場合など)、AWTへの依存が実際に必要かどうかを再評価できます。

CPU: パフォーマンスを向上させるためのより多くのCPU機能の有効化

ネイティブ・イメージ・ビルド・プロセスでは、CPUが現在有効になっているよりも多くの機能(AESやLSEなど)をサポートしていると判断しました。同じマシンまたは同じCPU機能をサポートする同様のマシンにアプリケーションをデプロイする場合は、ビルド時に-march=nativeを使用することを検討してください。このオプションを使用すると、Graalコンパイラは使用可能なすべてのCPU機能を使用できるため、アプリケーションのパフォーマンスが大幅に向上する可能性があります。-march=listを使用して、明示的にターゲット指定できるすべての使用可能なマシン・タイプをリストします。

G1GC: G1ガベージ・コレクタを使用したレイテンシとスループットの向上

G1ガベージ・コレクタはプラットフォームで使用できます。アプリケーションのレイテンシとスループットを向上させるために、ビルド時に--gc=G1を使用してこれを有効にすることを検討してください。詳細については、メモリー管理のドキュメントを参照してください。最高のピーク・パフォーマンスを実現するには、プロファイルに基づく最適化の使用も検討してください。

HEAP: 最大ヒープ・サイズの指定

「最大ヒープ・サイズ」を参照してください。

PGO: プロファイルに基づく最適化を使用したスループットの向上

プロファイルに基づく最適化を使用して、スループットを向上させるためにアプリケーションを最適化することを検討してください。これらの最適化により、Graalコンパイラは、アプリケーションをAOTコンパイルする際に、JITコンパイラとして実行される場合と同様に、プロファイリング情報を活用することができます。この場合は、次のステップを実行します:

  1. --pgo-instrumentを使用してアプリケーションをビルドします。
  2. 代表的なワークロードを使用してインストゥルメントされたアプリケーションを実行し、.iprofファイルの形式でプロファイリング情報を生成します。
  3. アプリケーションを再ビルドし、--pgo=<your>.iprofを使用してプロファイリング情報を渡し、最適化されたバージョンのアプリケーションを生成します。

関連ガイド: プロファイルに基づく最適化によるネイティブ実行可能ファイルの最適化

最高のピーク・パフォーマンスを得るには、G1ガベージ・コレクタの使用も検討してください。

QBM: クイック・ビルド・モードを使用したビルドの高速化

クイック・ビルド・モード(-Ob)を使用して、開発中のビルドを高速化することを検討してください。より正確には、このモードではGraalコンパイラによって実行される最適化の数が減るため、コンパイル・ステージの全体的な時間が短縮されます。クイック・ビルド・モードは開発に役立つだけでなく、生成された実行可能ファイルのサイズが小さくなることもあります。ただし、最適化の数が少なくなるため、実行可能ファイルの全体のピーク・スループットが低下する可能性があります。

リソース使用統計

ガベージ・コレクション

すべてのガベージ・コレクタに費やされた合計時間、合計GC時間を合計プロセス時間で割った値(パーセント)、およびガベージ・コレクションの合計数。コレクション数が多い、またはコレクタに費やされた時間が長い場合は、通常、システムがメモリー不足であることを示します。使用可能なメモリーの量を増やして、ネイティブ・バイナリのビルド時間を短縮します。

ピークRSS

オペレーティング・システムによって報告されるピーク常駐設定サイズこの値は、ビルド・プロセスで消費されるメモリーの最大量を示します。デフォルトでは、プロセスは使用可能なメモリー、つまり他のプロセスが使用するメモリーをスワップ・アウトすることなくオペレーティング・システムが利用できるメモリーのみを使用します。そのため、ビルドが遅い場合は、不要なアプリケーションを終了するなどしてメモリーを解放することを検討してください。デフォルトでは、利用可能な場合でも、ビルド・プロセスで32GB超は使用されないことに注意してください。GC統計に問題が表示されない場合は、システムの合計メモリーの量をピークRSSに近い値に減らして、運用コストを削減できます。

CPU負荷

プロセスで使用されたCPU時間を合計プロセス時間で割った値。CPUコアの数を増やして、ネイティブ・バイナリのビルド時間を短縮します。

マシンが読み取り可能なビルド出力

native-imageビルダーによって生成されるビルド出力は、人のために設計されており、新リリースごとに改良される可能性があります。このためツールによって解析することはできません。かわりに、-H:BuildOutputJSONFile=<file.json>オプションを使用して、マシンで読取り可能なJSON形式の出力を生成するようにビルダーに指示してください。これはモニタリング・ツールのビルドなどに使用できます。JSONファイルは、build-output-schema-v0.9.1.JSONで定義されたJSONスキーマに対して検証されます。JSONファイルは、ビルドが成功した場合にのみ生成されます。

次の例では、CI/CDビルド・パイプラインでこれを使用して、アクセス可能なメソッドの数が特定のしきい値を超えていないことを確認する方法を示します:

native-image -H:BuildOutputJSONFile=build.json HelloWorld
# ...
cat build.json | python3 -c "import json,sys;c = json.load(sys.stdin)['analysis_results']['methods']['reachable']; assert c < 12000, f'Too many reachable methods: {c}'"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
AssertionError: Too many reachable methods: 12128