私の JNI 関数は ProcessedImage オブジェクトを返します。関連する Java のクラス定義:
public class Thumbnail {
public int size;
public byte[] data;
}
public class ProcessedImage {
public Thumbnail[] thumbnails;
public byte[] hash;
}
私のネイティブ関数宣言は次のようになります。
public class ImageProcessor {
// Called from different JVM threads.
public static native ProcessedImage processImage(byte[] image);
// Only called once.
public static native initialize();
static {
System.loadLibrary("ImageProcessor");
initialize();
}
}
ここで、次のことを行うネイティブの初期化関数を書きたいと思います。
- ネイティブ ランドのグローバル マトリックスを埋めます。このマトリックスは、後で processImage ネイティブ関数で読み取られますが、この初期化後は不変です。
- GraphicsMagick の初期化関数を呼び出します。
(2)は一度呼び出すだけなので簡単です。(1)についてはどうしたらよいかわかりません。ここで配列を初期化できましたが、processImage 関数を呼び出す他の Java スレッドからは見えない可能性があります。これは静的ブロックにあるため、他の JVM スレッドが作成される前に実行されると思いますか? これは間違った仮定のようです。この配列が後で他の JVM スレッドから見えるようにする最善の方法は何ですか? このマトリックスへのアクセス/書き込みにロックを使用したくありません。これが純粋な C/C++ の場合、次のようにします。
__attribute__((constructor))
static void Initialize() {
// Initialize everything here.
}
もう 1 つの質問は、jclasses と jfieldID をキャッシュするのに最適な場所はどこですか? 初期化関数でそれらを調べて、グローバルとして保存する必要があります。クラスがアンロードされて再度ロードされた後、jclass と jfieldID が廃止される可能性があるため、これは適切な方法ではないことを読みました。標準的な方法では、クラス内の静的ブロックでこれを行う必要があるようです。このようなもの:
public class Thumbnail {
private static native initializeThumbnailNative();
static {
initializeThumbnailNative();
}
public int size;
public byte[] data;
}
クラスは、ネイティブ関数 processImage が呼び出されているスレッドとは異なるスレッドでロードおよびアンロードされる可能性があるため、ネイティブ関数はこれらのグローバル jclasses および jfieldID への変更を認識しない場合があります。これを処理するための推奨される方法は何ですか。ここでも、これらのフィールドへのアクセスをロックして、例外が発生したときにネイティブ メソッドを再試行できますが、それは正しくないようです。おそらく機能する可能性のある別のハックな方法は、Java ですべてのクラスの単一インスタンスを作成し、それらを静的として格納して、これらのクラスの少なくとも 1 つのインスタンスが常に存在し、アンロードされないようにすることです。だから、このようなもの:
public class ImageProcessor {
public static native ProcessedImage processImage(byte[] image);
public static native initialize();
// Create a static instance to prevent these classes from being unloaded.
private static Thumbnail thumbnail = new Thumbnail();
private static ProcessedImage processedImage = new ProcessedImage();
static {
System.loadLibrary("ImageProcessor");
initialize();
}
}
ただし、これが機能するかどうかはわかりません。マルチスレッド アプリケーションで jclasses と jFieldID のキャッシュを実現する最善の方法は何でしょうか? 長い質問を前もってお詫びしますが、最大限のコンテキストを提供したかったのです。