我想知道使用在 native 方法中创建并由该方法返回给调用者的本地引用有多安全。
这是一个简单的例子:
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 规范中了解到,本地引用仅在其创建的堆栈帧中有效,并在 native 方法返回时被清除。这是否意味着 obj 可以在 getAJObject 完成后进行垃圾回收,同时仍在 native 端而不返回 java?
这篇文章表明这段代码不安全: http://publib.boulder.ibm.com/infocenter/javasdk/v1r4m2/index.jsp?topic=%2Fcom.ibm.java.doc.diagnostics.142j9%2Fhtml%2Fhandlocref.html
但是我仍然看到 JNI 代码的示例正是这样做的!希望得到更多的澄清。
最佳答案
您可以安全地使用 func()
中的 getAJObject()
。当 JNI 调用正在进行时, native 对象 obj
的所有垃圾收集和本地引用管理都被卡住。让我来解决两种不同的情况:
如果您的代码从 Java 线程调用
func()
(即,如果可以在调用堆栈中找到 JVM),如果有一个 native Java通过一些调用链调用func()
的方法,然后这个本地方法定义了 JNI 本地引用框架的范围。或者,您的代码从 native 线程 调用
func()
,这需要调用jint AttachCurrentThread(JavaVM *vm, void **penv, void *args)或 jint AttachCurrentThreadAsDaemon(JavaVM *vm, void **penv, void *args)获取JNIEnv* jni
。在这种情况下,局部引用等的范围一直保留到该线程调用 jint DetachCurrentThread(JavaVM *vm) 为止。 .
请注意,在情况 2 中,如果线程在未调用 DetachCurrentThread() 的情况下终止,您的 JVM 将崩溃。
您还可以使用 jint PushLocalFrame(JNIEnv *env, jint capacity) 手动管理本地引用范围和 jobject PopLocalFrame(JNIEnv *env, jobject result) .
关于c++ - JNI - 返回在 native 函数中创建并由另一个 native 函数使用的 jobject,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22275035/