ネイティブイメージにおけるクラス初期化

Javaのセマンティクスでは、クラスは実行時に初めてアクセスされたときに初期化される必要があります。クラスの初期化は、次の2つの理由により、Javaアプリケーションを事前にコンパイルする場合に悪影響を及ぼします。

  • ネイティブ実行可能ファイルのパフォーマンスを大幅に低下させます。クラスへのすべてのアクセス(フィールドまたはメソッドを介して)では、クラスが既に初期化されていることを確認するためのチェックが必要になります。最適化を行わないと、パフォーマンスが2倍以上低下する可能性があります。
  • アプリケーションの起動に必要な計算量と時間が増加します。たとえば、単純な「Hello, World!」アプリケーションでは、300を超えるクラスを初期化する必要があります。

クラス初期化の悪影響を軽減するために、ネイティブイメージはビルド時のクラス初期化をサポートしています。実行可能ファイルをビルドするときにクラスを初期化できるため、実行時の初期化とチェックが不要になります。初期化されたクラスのすべての静的状態は実行可能ファイルに格納されます。ビルド時に初期化されたクラスの静的フィールドへのアクセスは、アプリケーションに対して透過的であり、クラスが実行時に初期化されたかのように機能します。

ただし、Javaクラスの初期化セマンティクスには、クラスの初期化ポリシーを複雑にするいくつかの制約があります。たとえば、

  • クラスが初期化されると、そのすべてのスーパークラスとデフォルトメソッドを持つスーパーインターフェースも初期化する必要があります。ただし、デフォルトメソッドのないインターフェースは初期化されません。この要件に対応するために、短期的な「関連スーパークラス」と、クラスおよびデフォルトメソッドを持つインターフェースのサブタイプに「関連サブタイプ」が使用されます。
  • ビルド時に初期化される型の関連スーパークラスもビルド時に初期化する必要があります。
  • 実行時に初期化される型の関連サブタイプも実行時に初期化する必要があります。
  • 実行時に初期化されるクラスのインスタンスは、実行可能ファイルに存在してはなりません。

ネイティブイメージのすぐに使えるエクスペリエンスを完全に享受し、ビルド時初期化のメリットを得るために、ネイティブイメージは次の2つのことを行います。

どのクラスが初期化されたのか、またその理由を追跡するには、コマンドラインオプション `-H:+PrintClassInitialization` を `native-image` ツールに渡します。このオプションは、必要に応じて `native image` ビルダーを設定するのに役立ちます。目標は、できるだけ多くのクラスをビルド時に初期化しながら、アプリケーションの正しいセマンティクスを維持することです。

ビルド時初期化 #

ネイティブイメージは、ガベージコレクター、重要なJDKクラス、逆最適化ツールなど、ほとんどのJDKクラスをビルド時に初期化します。ビルド時に初期化されるすべてのクラスについて、ネイティブイメージは適切なサポートを提供するため、ビルド時にクラス初期化が発生してもセマンティクスの一貫性が維持されます。ビルド時のクラス初期化が原因でJDKクラスが正しく動作しない問題を発見した場合は、問題を報告してください。

安全なクラスの自動初期化 #

アプリケーションクラスの場合、ネイティブイメージはビルド時に安全に初期化できるクラスを見つけようとします。クラスは、すべての関連スーパークラスが安全であり、クラスイニシャライザが安全でないメソッドを呼び出したり、他の安全でないクラスを初期化したりしない場合、安全であるとみなされます。

メソッドは、次の場合に安全でないとみなされます。

  • ネイティブコード(`System.out.println`など)を推移的に呼び出す場合:ネイティブコードは分析されないため、ネイティブイメージは違法なアクションが実行されているかどうかを認識できません。
  • 単一のターゲット(仮想メソッド)に還元できないメソッドを呼び出す場合。この制限により、静的イニシャライザの安全分析のための検索空間の爆発が回避されます。
  • ネイティブイメージによって置換される場合。置換されたメソッドのイニシャライザを実行すると、ホスティングJava仮想マシン(JVM)と生成された実行可能ファイルで異なる結果が得られます。その結果、安全分析では一部のメソッドが安全であるとみなされますが、それらを呼び出すと違法な状態になります。

安全であることが証明されたすべてのクラスのリストは、`native-image` ツールへのコマンドラインオプション `-H:+PrintClassInitialization` を介してファイルに出力されます。

注:クラスの初期化を明示的に指定することもできます。

お問い合わせ