Learn · concepts

JNIとは?モッダー向けのJavaネイティブインタフェース

JNI(Java Native Interface)は、JVMからC/C++を呼び出し、その逆を行うためのJavaに組み込まれたインターフェースです。MinecraftのModがネイティブライブラリをロードする標準的な方法です.

TRtrolPublished 1 min read

JNIとは、平易な言葉で言うと何ですか?

JNI(Java Native Interface)は、Javaの中で、JVM上の管理されたバイトコードと、CまたはC++で記述されたコンパイルされた機械語という、2つの世界をつなぐ部分です。メソッドにnativeキーワードが付き、かつ本体がない場合、実行時にJVMがロードされたネイティブライブラリ内の対応する関数にリンクします。そこから両者が引数や戻り値を交換します。

この境界線は一方通行ではありません。ネイティブ関数はJNIEnvポインタを受け取り、そのハンドルはJavaへのゲートウェイとなります。これにより、Javaのフィールドの読み書き、Javaメソッドの呼び出し、オブジェクトの構築、例外の発生といった呼び出しが可能になります。つまり、Javaが外部に呼び出すための橋が、Cが内部に呼び込むための橋でもあるのです。

MinecraftのModやクライアントがネイティブコードに触れるのはなぜですか?

ほとんどのJavaではJNIは必要ありません。ModがJNIに手を伸ばすのは、JVMだけでは処理できない場合、通常はグラフィックス、オーディオ、OS統合、または高速に処理する必要があるルーチンなどです。ネイティブライブラリが重い処理を行い、JNIはそのライブラリをロードし呼び出すための標準的な方法です.

実績のあるCライブラリを再利用する

既存のネイティブコードベースが既にその問題を解決しています。Javaで書き直すのは無駄な努力なので、このMODはそれにバインドします.

オペレーティングシステムに到達する

プラットフォームのいくつかの機能には、純粋なJava APIが存在しません。ネイティブ呼び出しが唯一の手段となります.

疾風の道

タイトな数値処理やローレベルなルーチンは、JVM 上でバイトコードとして実行するよりも、コンパイルされたネイティブコードとして実行する方が高速になることがある.

ドライブハードウェアとドライバー

レンダリング、サウンド、およびデバイスへのアクセスは、JNIがJava側に公開するネイティブライブラリの背後に頻繁に存在します.

JNI 呼び出しはエンドツーエンドでどのように機能しますか?

その流れはあらゆるプラットフォームで同一です。Java でメソッドを宣言し、対応する C 関数を共有ライブラリにコンパイルし、実行時にロードし、JVM に名前でリンクさせ、そしてクロス呼び出しを行います。関数名は固定パターンに従うため、JVM がそれを解決でき、生成されたヘッダーは実装すべき正確なシグネチャを記述しています。

ステップ何が起こるか
宣言Java メソッドに native キーワードを付与し、Java 側では空のままにします。
ビルドC または C++ 関数を共有ライブラリにコンパイルします。Windows では .dll、Linux では .so、macOS では .dylib です。
ロードJava はプログラム実行中に System.loadLibrary を呼び出してそのライブラリをロードします。
リンクJVM は各 native メソッドを名前修飾されたシグネチャによって対応する C 関数にマッチさせます。
呼び出しJava はメソッドを呼び出し、制御がネイティブコードに渡り、結果とともに戻ります。

JNI はあなたにいくらかかるのですか??

JNI は強力ですが、危険な側面もあります。 ネイティブコードが JVM の安全網の外で実行されるため、そこでエラーが発生すると、キャッチ可能な例外をスローする代わりに、プロセス全体がクラッシュします。 ネイティブ側で割り当てられたメモリはガベージコレクタから見えないため、手動で解放しない限り、メモリリークが蓄積します。 境界を越えるたびにオーバーヘッドが発生し、タイトなループ内で境界を越えて呼び出すとコストがかかります。 また、ネイティブビルドはプラットフォームに依存するため、Windows の .dll は、別のコンパイルなしに Linux では読み込まれません.

それが買うもの

  • 既存のCおよびC++ライブラリへの直接アクセス
  • JVMでは到達できないOSおよびハードウェア機能への道
  • 最も重要なルーチンでのネイティブ速度の実行

にかかる費用

  • ネイティブクラッシュはJVM全体をダウンさせる可能性がある
  • ガベージコレクタのバックアップなしでの手動メモリ管理
  • プラットフォームごとのビルドの維持と配布
  • ホットループにおける境界を越えるオーバーヘッド

JNI と Foreign Function and Memory API

JNI は当初の仕組みですが、これだけではありません。より新しい Java のリリースには、Foreign Function and Memory (FFM) API が搭載されており、これは、より少ない記述量とより厳格な安全性を確保しながらネイティブコードを呼び出すように設計されています。JNI は、どこにでも存在し、十分に理解されているため、既存のツールチェーンで依然として優勢です。

JNIFFM API
登場黎明期からのオリジナル近年のリリースで追加されたモダン
定型コード生成されたヘッダー、名前修飾された C 関数Java で定義されたメソッドハンドル、不要な C の補助コードなし
メモリ安全性手動; 間違いは JVM を破損させる可能性があるより強力なチェックを備えた境界付きセグメント
採用状況既存のライブラリで普遍的成長中、新しいコードベース

よくある質問

Terminusを入手

JVM内部を実際に読んだ人たちによって構築されました。