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.
}

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

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

4

2 回答 2

1

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

无论如何,您可以查看 JNI_OnLoad

于 2013-10-25T06:21:42.813 回答
1

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

在退出时获取的 JNI 方法之后,jclassjobject可能会变得无效,更不用说跨类加载了。如果您完全静态存储这些,则必须将其作为“全局参考”或“弱参考”进行。

于 2013-07-24T23:11:09.437 回答