C++ JNI-返回在本机函数中创建并由另一个本机函数使用的jobject
我想知道使用在本机方法中创建并由该方法返回给调用方的本地引用有多安全 下面是一个简单的例子:C++ JNI-返回在本机函数中创建并由另一个本机函数使用的jobject,c++,java-native-interface,C++,Java Native Interface,我想知道使用在本机方法中创建并由该方法返回给调用方的本地引用有多安全 下面是一个简单的例子: jobject getAJObject(JNIEnv* jni) { jobject obj = jni->CallStaticVoidMethod(...); // java method that returns a jobject return obj; } void func(JNIEnv* jni) { jobject obj = getAJObject(jni
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代码的例子,它们正是这样做的!希望得到更多的澄清 您可以从
func()
安全地使用getAJObject()
。当JNI调用进行时,本机对象obj
的所有垃圾收集和本地引用管理都被冻结。让我谈谈两种不同的情况:
func()
(即,如果可以在调用堆栈中找到JVM),如果有一个nativeJava方法通过一些调用链调用func()
,那么这个native方法定义了JNI本地引用框架的范围func()
,本机线程需要调用或获取JNIEnv*jni
。在这种情况下,本地引用等的范围保持不变,直到该线程调用为止您还可以手动管理本地引用范围,使用和。在其上使用
NewGlobalRef
,返回它,然后在完成时从另一个函数中使用deletegobalref
。。否则,您将从func
访问getAJObject
堆栈上分配的对象。。结果是UB希望这不是答案。我可以在func中定义一个jobject,并将其作为参数传递给getAOObject并在其中赋值吗?您不能这样做,因为对象超出范围时会被销毁。这仍然相当于归还它。因此,再次强调,这样做将是未定义的行为(除非您像前面讨论的那样将其设置为globalref)。听起来您正在尝试创建一个全局引用。。有什么特别的原因吗?全局引用有一个限制,您必须确保调用DeleteGlobalRef。这很好,但我需要在两个地方删除globalref(还有一个catch子句)。这只是一个小小的抱怨,但如果有其他选择的话,我会更喜欢它。而且,看看android的源代码,他们似乎也在做同样的事情。(查看createBitmap)这就是我认为它是如何工作的,有没有专门说明这一点的文档?JNI规范在一个地方说“本地引用在本机方法调用期间有效”,同时还说“本地引用在本机方法返回Java后自动释放”。()想补充一点,我在android参考中发现,“如果使用AttachCurrentThread附加本机线程,则在线程分离之前,您正在运行的代码永远不会自动释放本地引用。”。你说得对,亚历克斯!现在,我只想确保在您描述的案例1中,GC不会在本机代码中运行。此源声明它们将被删除(由CantChooseSuerNames链接):[“当本机方法返回时,所有本地引用将自动删除。”Re:Case 1。这正是“本地引用在本机方法调用期间有效”的意思!因此函数getAJObject()这不是他们说的“本机方法调用”时所指的吗?本机方法调用具体指的是从Java调用的函数?如果是这样的话,这可能就是我所有困惑的根源。