我的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();
}
}
现在我想编写一个执行以下操作的本机初始化函数:
(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缓存的最佳方法是什么?我提前为这个冗长的问题道歉,但我想提供最大的背景。
答案 0 :(得分:1)
我读到这不是一个好习惯,因为在类被卸载并再次加载后,jclass和jfieldID可能会过时。
jclass
或jobject
在退出后获取的JNI方法之后可能无效,更不用说跨类加载了。如果你静态地存储这些,你必须这样做'全局引用'或'弱引用'。
答案 1 :(得分:1)
对不起,我迟到了,我睡过头了(好几个月,是的流行音乐参考)。
无论如何,您可以查看JNI_OnLoad