我想知道使用在本机方法中创建并由该方法返回给调用者的本地引用是多么安全。
这是一个简单的例子:
jobject getAJObject(JNIEnv* jni) {
jobject obj = jni->CallStaticVoidMethod(...); // java method that returns a jobject
return obj;
}
void func(JNIEnv* jni) {
jobject obj = getAJObject(jni);
// Code that uses obj
...
}
我已经测试了这段代码并且它确实运行良好,但我担心它不安全。我从阅读JNI规范的理解是本地引用仅在它创建的堆栈框架中有效,并在本机方法返回时清除。这是否意味着obj可以在getAJObject完成后收集垃圾,而仍然在本机端而不返回到java?
但是我仍然看到JNI代码的例子就是这样做的!希望得到更多的澄清。
答案 0 :(得分:2)
您可以安全地使用getAJObject()
中的func()
。在JNI调用正在进行时,冻结本机对象obj
的所有垃圾收集和本地引用管理。让我谈谈两种不同的情况:
如果您的代码从Java线程调用func()
(即如果可以在调用堆栈中找到JVM),那么如果有一个 native Java方法调用了{{ 1}}通过一些调用链,然后这个 本机方法 定义了JNI本地引用框架的范围。
或者,您的代码从原生线程调用func()
,需要调用jint AttachCurrentThread(JavaVM *vm, void **penv, void *args)或jint AttachCurrentThreadAsDaemon(JavaVM *vm, void **penv, void *args)来获取func()
。在这种情况下,本地引用的范围等仍然存在,直到该线程调用jint DetachCurrentThread(JavaVM *vm)。
请注意,如果 2 ,如果线程在没有调用 DetachCurrentThread()的情况下死亡,那么您的JVM将崩溃。
您还可以使用jint PushLocalFrame(JNIEnv *env, jint capacity)和jobject PopLocalFrame(JNIEnv *env, jobject result)手动管理本地参考范围。