ネイティブイメージ

ネイティブイメージは、Javaコードを事前にバイナリ、つまりネイティブ実行ファイルにコンパイルする技術です。ネイティブ実行ファイルには、実行時に必要なコード、つまりアプリケーションクラス、標準ライブラリクラス、言語ランタイム、JDKからの静的にリンクされたネイティブコードのみが含まれます。

ネイティブイメージによって生成された実行ファイルには、いくつかの重要な利点があります。

  • Java仮想マシンが必要とするリソースのごく一部を使用するため、実行コストが低い
  • ミリ秒単位で起動する
  • ウォームアップなしで、すぐに最高のパフォーマンスを発揮する
  • 高速で効率的なデプロイメントのために、軽量なコンテナイメージにパッケージ化できる
  • 攻撃対象領域を縮小する

ネイティブ実行ファイルは、アプリケーションクラスとその他のメタデータを処理して、特定のオペレーティングシステムとアーキテクチャ用のバイナリを作成する、ネイティブイメージビルダーまたはnative-imageによって作成されます。まず、native-imageツールは、アプリケーションの実行時に到達可能なクラスとメソッドを決定するために、コードの静的解析を実行します。次に、クラス、メソッド、およびリソースをバイナリにコンパイルします。このプロセス全体は、Javaソースコードのバイトコードへのコンパイルと明確に区別するために、ビルド時と呼ばれます。

native-imageツールは、デフォルトのネイティブ実行ファイル、またはネイティブ共有ライブラリをビルドするために使用できます。このクイックスタートガイドは、ネイティブ実行ファイルのビルドに焦点を当てています。ネイティブ共有ライブラリの詳細については、こちらを参照してください。

ネイティブイメージの用語に慣れ、この技術をよりよく理解するために、ネイティブイメージの基礎を読むことをお勧めします。

目次 #

前提条件 #

GraalVMインストールの`bin`ディレクトリにある`native-image`ツールは、ローカルツールチェーン(Cライブラリのヘッダーファイル、`glibc-devel`、`zlib`、`gcc`、および/または`libstdc++-static`)に依存します。これらの依存関係は、マシン上のパッケージマネージャーを使用してインストールできます(まだインストールされていない場合)。前提条件を満たすための手順を見つけるには、オペレーティングシステムを選択してください。

Linux

Oracle Linuxでは、`yum`パッケージマネージャーを使用します

sudo yum install gcc glibc-devel zlib-devel

一部のLinuxディストリビューションでは、さらに`libstdc++-static`が必要になる場合があります。オプションのリポジトリが有効になっている場合(Oracle Linux 7では *ol7_optional_latest*、Oracle Linux 8では *ol8_codeready_builder*、Oracle Linux 9では *ol9_codeready_builder*)、`libstdc++-static`をインストールできます。

Ubuntu Linuxでは、`apt-get`パッケージマネージャーを使用します

sudo apt-get install build-essential zlib1g-dev

その他のLinuxディストリビューションでは、`dnf`パッケージマネージャーを使用します

sudo dnf install gcc glibc-devel zlib-devel libstdc++-static

MacOS

macOSでは、`xcode`を使用します

xcode-select --install

Windows

Windowsでネイティブイメージを使用するには、Visual Studio 2022バージョン17.6.0以降、およびMicrosoft Visual C ++(MSVC)をインストールします。 2つのインストールオプションがあります

  • Windows 11 SDK(またはそれ以降のバージョン)を使用してVisual Studio Build Toolsをインストールする
  • Windows 11 SDK(またはそれ以降のバージョン)を使用してVisual Studioをインストールする

ネイティブイメージはPowerShellまたはコマンドプロンプトの両方で実行され、適切なVisual Studioインストールが見つかった場合は、Windowsでビルド環境を自動的に設定します。

詳細については、WindowsでのGraalVMとネイティブイメージの使用を参照してください。

MavenまたはGradleを使用してネイティブ実行ファイルをビルドする #

ネイティブ実行ファイルのビルド、テスト、および設定を自動化するために、ネイティブイメージ用のMavenおよびGradleプラグインを提供しています。

Maven #

ネイティブイメージ用Mavenプラグインは、Apache Mavenを使用してJavaアプリケーションをネイティブ実行ファイルにコンパイルするためのサポートを追加します。

  1. お気に入りのIDEまたはターミナルから、次の構造で「helloworld」という名前の新しいMaven Javaプロジェクトを作成します
     ├── pom.xml
     └── src
         ├── main
         │   └── java
         │       └── com
         │           └── example
         │               └── App.java
    

    たとえば、quickstartアーキタイプを使用して新しいMavenプロジェクトを作成するには、次のコマンドを実行できます

     mvn archetype:generate -DgroupId=com.example -DartifactId=helloworld -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
    
  2. プロジェクトをコンパイルし、実行可能なJARファイルにアセンブルするための通常のMavenプラグインを *pom.xml* ファイルに追加します
     <build>
         <plugins>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-compiler-plugin</artifactId>
                 <version>3.12.1</version>
                 <configuration>
                     <fork>true</fork>
                 </configuration>
             </plugin>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-jar-plugin</artifactId>
                 <version>3.3.0</version>
                 <configuration>
                     <archive>
                         <manifest>
                             <mainClass>com.example.App</mainClass>
                             <addClasspath>true</addClasspath>
                         </manifest>
                     </archive>
                 </configuration>
             </plugin>
         </plugins>
     </build>
    
  3. *pom.xml* に次のプロファイルを追加して、ネイティブイメージ用Mavenプラグインを有効にします
     <profiles>
       <profile>
         <id>native</id>
         <build>
           <plugins>
             <plugin>
               <groupId>org.graalvm.buildtools</groupId>
               <artifactId>native-maven-plugin</artifactId>
               <version>${native.maven.plugin.version}</version>
               <extensions>true</extensions>
               <executions>
                 <execution>
                 <id>build-native</id>
                   <goals>
                     <goal>compile-no-fork</goal>
                   </goals>
                   <phase>package</phase>
                 </execution>
                 <execution>
                 <id>test-native</id>
                   <goals>
                     <goal>test</goal>
                   </goals>
                   <phase>test</phase>
                 </execution>
               </executions>
             </plugin>
           </plugins>
         </build>
       </profile>
     </profiles>
    

    `version`プロパティを最新のプラグインバージョンに設定します(たとえば、`<properties>`要素で`<native.maven.plugin.version>`を介してバージョンを指定します)。

  4. プロジェクトをコンパイルし、1つのステップでネイティブ実行ファイルをビルドします
     mvn -Pnative package
    

    `helloworld`という名前のネイティブ実行ファイルは、プロジェクトの *target/* ディレクトリに作成されます。

  5. 実行ファイルを実行します
     ./target/helloworld 
    

    これで、Mavenを使用してJavaアプリケーションのネイティブ実行ファイルを正常に作成できました。

ネイティブイメージビルド用Mavenプラグインは、リソースの自動検出、必要な構成の生成、ネイティブ実行ファイルでのJUnitプラットフォームテストの実行など、より複雑なアプリケーションに必要な多くの他の機能を提供します。 プラグインリファレンスドキュメントに記載されています。

Gradle #

ネイティブイメージ用Gradleプラグインは、Gradleビルドツールを使用してJavaアプリケーションをネイティブ実行ファイルにコンパイルするためのサポートを追加します。

  1. お気に入りのIDEまたはターミナルから、次の構造で「helloworld」という名前の新しいGradle Javaプロジェクトを作成します
     ├── app
     │   ├── build.gradle
     │   └── src
     │       ├── main
     │       │   ├── java
     │       │   │   └── org
     │       │   │       └── example
     │       │   │           └── App.java
     │       │   └── resources
    

    たとえば、`java`プラグインを使用して新しいGradleプロジェクトを初期化します

    • 新しいディレクトリを作成して入力します
        mkdir helloworld && cd helloworld
      
    • プロジェクトを生成します
        gradle init --project-name helloworld --type java-application --test-framework junit-jupiter --dsl groovy
      

      プロンプトに従います。このコマンドは、必要なディレクトリ構造とビルドファイルを使用して新しいJavaアプリケーションをセットアップします。

  2. プロジェクトの *build.gradle* ファイルの`plugins`セクションに次を追加して、ネイティブイメージ用Gradleプラグインを有効にします
     plugins {
     // ...
     id 'org.graalvm.buildtools.native' version 'x.x.x'
     }
    

    `'x.x.x'`バージョン値に最新のプラグインバージョンを指定します。

  3. `./gradlew nativeCompile`を実行して、ネイティブ実行ファイルをビルドします
     ./gradlew nativeCompile
    

    `app`という名前のネイティブ実行ファイルは、プロジェクトの *app/build/native/nativeCompile/* ディレクトリに作成されます。

  4. ネイティブ実行ファイルを実行します
     ./app/build/native/nativeCompile/app 
    

    これで、Gradleを使用してJavaアプリケーションのネイティブ実行ファイルを正常に作成できました。

ネイティブイメージビルド用Gradleプラグインには、リソースの自動検出、必要な構成の生成、ネイティブ実行ファイルでのJUnitプラットフォームテストの実行など、より複雑なアプリケーションに必要な多くの他の機能があります。 プラグインリファレンスドキュメントに記載されています。

`native-image`ツールを使用してネイティブ実行ファイルをビルドする #

`native-image`ツールは、Javaバイトコードを入力として受け取ります。クラスファイル、JARファイル、またはモジュール(Java 9以降)からネイティブ実行ファイルをビルドできます。

クラスから #

現在の作業ディレクトリにあるJavaクラスファイルからネイティブ実行ファイルをビルドするには、次のコマンドを使用します

native-image [options] class [imagename] [options]

たとえば、HelloWorldアプリケーションのネイティブ実行ファイルをビルドします。

  1. このコードを *HelloWorld.java* という名前のファイルに保存します
     public class HelloWorld {
         public static void main(String[] args) {
             System.out.println("Hello, Native World!");
         }
     }
    
  2. コンパイルして、Javaクラスからネイティブ実行ファイルをビルドします
     javac HelloWorld.java
     native-image HelloWorld
    

    現在の作業ディレクトリにネイティブ実行ファイル`helloworld`が作成されます。

  3. アプリケーションを実行します

     ./helloworld
    

    時間をかけて使用されたリソースを確認できます

     time -f 'Elapsed Time: %e s Max RSS: %M KB' ./helloworld
     # Hello, Native World!
     # Elapsed Time: 0.00 s Max RSS: 7620 KB
    

JARファイルから #

現在の作業ディレクトリにあるJARファイルからネイティブ実行ファイルをビルドするには、次のコマンドを使用します

native-image [options] -jar jarfile [imagename]

`native-image`のデフォルトの動作は`java`コマンドと一致しています。つまり、`java`で通常行うように、`-jar`、`-cp`、`-m`オプションを渡してネイティブイメージでビルドできます。たとえば、`java -jar App.jar someArgument`は`native-image -jar App.jar`および`./App someArgument`になります。

JARファイルからネイティブ実行ファイルをビルドするには、このガイドに従ってください

モジュールから #

モジュール化されたJavaアプリケーションをネイティブ実行ファイルに変換することもできます。

Javaモジュールからネイティブ実行ファイルをビルドするコマンドは次のとおりです

native-image [options] --module <module>[/<mainclass>] [options]

モジュール化されたJavaアプリケーションからネイティブ実行ファイルを生成する方法の詳細については、HelloWorld Javaモジュールをネイティブ実行ファイルにビルドするを参照してください。

ビルド設定 #

ビルドプロセスを設定するために`native-image`ツールに渡すことができるオプションは多数あります。 `native-image --help`を実行して、完全なリストを表示します。 `native-image`に渡されたオプションは、左から右に評価されます。

さまざまなビルド調整とビルド時の設定の詳細については、ネイティブイメージのビルド設定を参照してください。

ネイティブイメージは、ビルド中に進行状況とさまざまな統計を出力します。出力とさまざまなビルドフェーズの詳細については、ビルド出力を参照してください。ネイティブ実行ファイルの内容に関する詳細な洞察については、ビルドレポートを参照してください。

ネイティブイメージとサードパーティライブラリ #

外部ライブラリを使用する、より複雑なアプリケーションの場合、`native-image`ツールにメタデータを提供する必要があります。

`native-image`を使用したスタンドアロンバイナリのビルドは、「閉世界の前提」の下で行われます。 `native-image`ツールは、アプリケーション内でどのクラス、メソッド、およびフィールドに到達可能であり、ネイティブ実行ファイルに含める必要があるかを確認するために分析を実行します。分析は静的です。アプリケーションを実行しません。これは、実行時に呼び出すことができるアプリケーション内のすべてのバイトコードが、ビルド時に認識(観察および分析)される必要があることを意味します。

分析では動的クラスロードのいくつかのケースを特定できますが、Javaネイティブインターフェイス(JNI)、Javaリフレクション、動的プロキシオブジェクト、またはクラスパスリソースのすべての使用法を常に網羅的に予測できるとは限りません。 Javaのこれらの動的機能に対処するには、リフレクション、プロキシなどを使用するクラスの詳細、または動的にロードされるクラスを分析に通知します。これを実現するには、`native-image`ツールにJSON形式の設定ファイルを提供するか、コードでメタデータを事前に計算します。

メタデータ、その提供方法、およびサポートされているメタデータの種類の詳細については、到達可能性メタデータを参照してください。アプリケーションのメタデータを自動的に収集するには、メタデータの自動収集を参照してください。

一部のアプリケーションでは、ネイティブイメージでコンパイルするために追加の設定が必要になる場合があります。詳細については、ネイティブイメージ互換性ガイドを参照してください。

ネイティブイメージは、カスタムAPIを介してネイティブ言語と相互運用することもできます。このAPIを使用すると、Javaアプリケーションへのカスタムネイティブエントリポイントを指定し、それをネイティブ共有ライブラリに組み込むことができます。詳細については、ネイティブコードとの相互運用性を参照してください。

さらに読む #

この入門ガイドは、ネイティブイメージの使用経験が少ない、またはまったくない新規ユーザーを対象としています。これらのユーザーは、さらに深く進む前に、ネイティブイメージの基本ページを確認して、いくつかの重要な側面を理解することを強くお勧めします。

ユーザーガイドを確認して、ネイティブイメージの経験を積み、デモ例を見つけ、潜在的な使用シナリオについて学習してください。

段階的な学習プロセスについては、ネイティブイメージのビルドの概要およびビルド構成のドキュメントを確認してください。

実践的な経験を得るために、インタラクティブなワークショップへの参加を検討してください。Luna Labsにアクセスし、「ネイティブイメージ」を検索してください。

潜在的なバグを発見した場合は、GitHubでIssueを提出してください。

ネイティブイメージに貢献したい場合は、標準の貢献ワークフローに従ってください。

お問い合わせ