0

私の 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();
  }
}

ここで、次のことを行うネイティブの初期化関数を書きたいと思います。

  1. ネイティブ ランドのグローバル マトリックスを埋めます。このマトリックスは、後で processImage ネイティブ関数で読み取られますが、この初期化後は不変です。
  2. 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 のキャッシュを実現する最善の方法は何でしょうか? 長い質問を前もってお詫びしますが、最大限のコンテキストを提供したかったのです。

4

2 に答える 2

1

クラスがアンロードされて再度ロードされた後、jclass と jfieldID が廃止される可能性があるため、これは良い方法ではないことを読みました。

jclassorjobjectは、JNI メソッドが出口で取得された後に無効になる可能性があり、クラスのロード間は言うまでもありません。これらを静的に保存する場合は、'global refs' または 'weak refs' として保存する必要があります。

于 2013-07-24T23:11:09.437 に答える