ネイティブ・イメージ

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

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

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

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

ネイティブ・イメージの用語に慣れてテクノロジの理解を深めるには、ネイティブ・イメージの基本を読むことをお薦めします。

目次

前提条件

GraalVMインストールのbinディレクトリで使用可能なnative-imageツールは、ローカル・ツールチェーン(Cライブラリ、glibc-develzlibgccまたは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つのインストール・オプションがあります:

ネイティブ・イメージは、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 someArgumentnative-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 Native Interface (JNI)、Javaリフレクション、動的プロキシ・オブジェクトまたはクラスパス・リソースのすべての使用状況を常に完全に予測できるわけではありません。Javaのこれらの動的機能を処理するには、リフレクション、プロキシなどを使用するクラスの詳細、または動的にロードされるクラスについて分析に通知します。これを実現するには、native-imageツールにJSON形式の構成ファイルまたはコード内の事前計算メタデータを指定します。

メタデータ、その指定方法およびサポートされているメタデータ・タイプについてさらに学習するには、到達可能性メタデータを参照してください。アプリケーションのメタデータを自動的に収集するには、メタデータの自動収集に関する項を参照してください。

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

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

その他の情報

このスタート・ガイドは、新しいユーザーまたはネイティブ・イメージの使用経験がほとんどないユーザーを対象としています。このようなユーザーは、ネイティブ・イメージの基本を確認して、いくつかの重要な側面をよく理解してから詳細に進むことを強くお薦めします。

ユーザー・ガイドをチェックして、ネイティブ・イメージの使用経験を深め、デモの例を見つけ、潜在的な使用シナリオについて学習します。

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

実践的な経験を得るために対話型ワークショップを実行することを検討してください。Lunaラボに移動し、「ネイティブ・イメージ」を検索します。

考えられるバグを見つけた場合は、GitHubで問題を送信してください。

ネイティブ・イメージにコントリビュートする場合は、標準のコントリビュートのワークフローに従ってください。