アプリケーションミスのトラブルの確実な事前防止のためには、(CやC++等を使用した)ネイティブプログラムを、Java Native Interface(JNI)経由で利用してはいけません。実現しようとしている機能が、Javaにより記述できないか設計段階で十分に検討を行ってください。やむをえず利用する場合でも、JNIの利用は最小限にし、十分な確認とデバッグを実施してください。
JNIを利用する場合の前提スキルとして、以下は必須です。
C/C++によるマルチスレッドプログラミングの経験がある
トラブル発生時、自分でデバッグできる
注意
ファイナライズ処理を期待したリソース管理は、行わないでください。JNI関連で、もっともトラブルが多いのは、ネイティブプログラム側で確保したメモリの後処理漏れです。例えば、次のようなプログラミングをしてはいけません。
------- Java --------------- class A { native long nativeAlloc(); native void nativeFree(long a); long address; A() { address = nativeAlloc(); } public void finalize() { nativeFree(address); } } ------- Java --------------- ------- C ------------------ JNIEXPORT jlong JNICALL Java_A_nativeAlloc(JNIEnv *env, jobject o) { return (jlong)malloc(10); } JNIEXPORT void JNICALL Java_A_nativeFree(JNIEnv *env, jobject o, jlong p) { free((void*)p); } ------- C -------------------
注意
エラー処理は、必ず行ってください。ネイティブプログラム側でJNI関数呼び出しをしたとき、色々なケースでJavaレベルのエラーになることがあります。このエラーに対する後処理をネイティブプログラム側で行わないと、例外がスローされている状態のままになり、それ以降のJNI関数の呼び出しに失敗し、アプリケーションが正しく動作しません。
なお「JNI関数」とは、以下のJNI仕様書に記述されている関数のことです。
https://docs.oracle.com/javase/jp/8/docs/technotes/guides/jni/spec/functions.html |
これらを使う場合は、その度にExceptionOccurredを使用しエラーチェックをする必要があります。
Solaris、Linux上でJNIを利用される場合は、連携するネイティブプログラムまたは、ネイティブライブラリにおいてシグナルハンドラの書き替えを絶対に行わないでください。
なお、シグナル連鎖機能(Signal Chaining)を利用する場合、マルチスレッド環境におけるシグナル動作など、OSやJava VM自身のシグナル動作およびプログラミングについての知識が前提として必要です。
安定稼動が要求されるシステムの設計においては、この機能の使用もお勧めできません。