JNI初始化函数和缓存类和字段

时间:2013-07-24 22:46:28

标签: java c++ java-native-interface

我的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 init函数。
  3. (2)很容易,因为它需要被调用一次。我不知道该怎么做(1)。我可以在这里初始化数组,但是调用processImage函数的其他Java线程可能看不到它。我可以假设,因为这是在一个静态块中,这将在创建任何其他JVM线程之前执行吗?这似乎是一个错误的假设。对于我来说,确保此数组稍后可供其他JVM线程看到的最佳方法是什么?我不想使用锁来访问/写入这个矩阵。如果这是纯粹的C / C ++,我会做这样的事情:

    __attribute__((constructor))
    static void Initialize() {
      // Initialize everything here.
    }
    

    另一个问题是缓存jclasses和jfieldIDs的最佳位置是什么?我应该在初始化函数中查找它们并将它们存储为全局变量。我读到这不是一个好习惯,因为在类被卸载并再次加载后,jclass和jfieldID可能会过时。标准做法似乎应该在类中的静态块中执行此操作。像这样:

    public class Thumbnail {
      private static native initializeThumbnailNative();
      static {
        initializeThumbnailNative();
      }
      public int size;
      public byte[] data;
    }
    

    由于类可以在与我的本机函数processImage不同的线程上加载和卸载,因此我的本机函数可能看不到对这些全局jclasses和jfieldID的更改。建议的方法是什么?我再次可以锁定对这些字段的访问权限并在异常时重试本机方法,但这似乎不对。另一种可能有用的hacky方法是我可以在java中创建所有类的单个实例并将它们存储为静态,这样这些类总是至少有一个实例,并且它们永远不会被卸载。所以像这样:

    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和jFieldIDs缓存的最佳方法是什么?我提前为这个冗长的问题道歉,但我想提供最大的背景。

2 个答案:

答案 0 :(得分:1)

  

我读到这不是一个好习惯,因为在类被卸载并再次加载后,jclass和jfieldID可能会过时。

jclassjobject在退出后获取的JNI方法之后可能无效,更不用说跨类加载了。如果你静态地存储这些,你必须这样做'全局引用'或'弱引用'。

答案 1 :(得分:1)

对不起,我迟到了,我睡过头了(好几个月,是的流行音乐参考)。

无论如何,您可以查看JNI_OnLoad