JNI中删除jclass和jobject的引用

3
这是删除jclass和jobject引用的正确方式吗?
JNIEXPORT void JNICALL Java_method(JNIEnv *env,jobject, jobject objArray)
{
    int n = env->GetArrayLength(objArray);

    for (int i = 0; i<n ; ++i)
    {
        jobject sObject = env->GetObjectArrayElement(objArray, i);
        jclass sObjectClass = env->GetObjectClass(sObject);

        dosomething(sObjectClass, sObject);

        env->DeleteLocalRef(sObject);
        env->DeleteLocalRef(sObjectClass);
    }

是的,对于本地引用来说,这是正确的。而且它应该可以防止引用表溢出。 - undefined
为什么你在循环中需要使用GetObjectClass呢?你是否期望数组中的元素具有不同的类型? - undefined
1个回答

4

简短回答:

是的,这是正确的方法。调用DeleteLocalRef并不是必需的,但如果objArray很大或函数执行时间很长,则它是有用的。

更详细的答案:

Oracle参考文档说明:

基本类型(如整数、字符等)在Java和本机代码之间进行复制。另一方面,任意Java对象都是通过引用传递的。虚拟机必须跟踪所有已传递给本机代码的对象,以便垃圾收集器不释放这些对象。反过来,本机代码必须有一种方法来通知虚拟机它不再需要这些对象。此外,垃圾收集器必须能够移动由本机代码引用的对象。

因此,任何本地代码使用的对象都必须标记为从本地代码的角度有资格进行垃圾回收,当本地代码不再需要该对象时。JNI有两种类型的引用-全局和局部引用。从GetObjectArrayElementGetObjectClass检索到的引用是局部引用,因为:

JNI函数返回的所有Java对象都是局部引用。

虚拟机在本地函数返回时自动释放所有局部引用。因此,在大多数情况下,不需要通过DeleteLocalRef来释放这些引用,因为虚拟机会自动释放它们。

但是,如果一个函数调用中需要大量的局部引用或者调用时间很长,那么在这些引用不再需要并且等待函数返回之前就明确释放它们是值得的。释放有助于虚拟机进行更好的内存管理。


1
如果您的本地代码位于调用堆栈的底部,您必须释放本地引用,否则JVM可能会耗尽。如果您保留这些引用,您可以将它们转换为全局引用。本地代码如何位于堆栈底部呢?如果您的本地代码创建了JVM,或者您的本地代码创建了本地线程。 - undefined
@Wheezil:您说得对,但我猜问题不是关于本地代码在堆栈底部的情况。至少问题中的代码表明这是从jvm调用的本地函数。 - undefined
是的,当然你是对的。我应该注意到我的评论是罕见的例外,而不是规则。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接