即使在deleteLocalRef之后jni表溢出

时间:2012-08-23 09:01:11

标签: android reference java-native-interface overflow

当我运行代码时,我收到错误“添加到JNI本地ref表失败有512个条目”

这是我的代码:

jstring pJNIData = pJNIEnv->NewStringUTF ( variables[0].GetStringValue() );

pJNIEnv->CallStaticVoidMethod ( pJNIActivityClass, pJNIMethodIDStartTime, pJNIData ) ;

pJNIEnv->DeleteLocalRef(pJNIData);

我已经阅读了几条建议,但它们都没有用!尽管DeleteLocalRef,但它无法正常工作。该函数用于一个字面上调用所有函数的分析器......

2 个答案:

答案 0 :(得分:2)

当一个名为Java代码的JNI方法(在我的例子中,该方法不是静态的)时,我已经看到了这一点。据我所知,当从JNI调用Java方法时,未使用的本地引用 会自动删除(我的意思是,直到顶级JNI函数返回)。

IIRC或者已经有关于日志中内存对象的信息,或者我可以添加一些日志记录;根据这些信息,我发现了之前没有提到的垃圾。它们是两个数组和一个类,在后续调用中创建但不是垃圾回收。

// in a function that calls a Java method from JNI
jbyteArray srcArray = env->NewByteArray(len);
jclass cls = env->FindClass("com/something/MyClass");
jmethodID mid = env->GetMethodID(cls, "mymethod", "([BI)[B");
jbyteArray resArray = (jbyteArray)env->CallObjectMethod(obj, mid, srcArray, XXXX);

...
env->DeleteLocalRef(cls);
env->DeleteLocalRef(resArray);
env->DeleteLocalRef(srcArray);
// no need to do anything with mid

请注意,虽然这三个本地参考文献的获得方式不同,但所有这些参考文献都悬而未决。

有用的链接: http://www.netmite.com/android/mydroid/dalvik/docs/jni-tips.html#local_vs_global_references (或找到Dalvik VM docs dalvik / docs / jni-tips.html并找到“本地与全局参考”部分)

JNI返回的每个对象都是“本地引用”。这意味着它在当前线程中当前本机方法的持续时间内有效。即使在本机方法返回后对象本身继续存在,引用也无效。这适用于jobject的所有子类,包括jclass和jarray。 [...]注意:方法和字段ID只是32位标识符,而不是对象引用,不应传递给NewGlobalRef。 GetStringUTFChars和GetByteArrayElements等函数返回的原始数据指针也不是对象。

答案 1 :(得分:0)

我想如果有其他人遇到这个问题我会填补。这是一个奇怪的案例让我困惑了几个小时!

好的,所以我有一个NDK应用程序,被调用的Java代码位于运行时加载的apk中。我不知道运行时加载是否会以任何方式影响它,但我想我应该提一下。

现在在c ++方法中,我使用find class和getmethodid将constuctor转换为HashMap并调用它来获取一个新的HashMap实例。然后我使用jni调用从c ++端填充HashMap。到现在为止还挺好。 然后我将HashMap传递给java代码,并且所有这些都按预期工作。一旦java代码返回,我就在HashMap上调用DeleteLocalRef。不会抛出任何错误,但不会删除引用

这只有在我最终运行512个本地引用(来自对此函数的多次调用)时才出现,并且错误转储显示localref存储中的最后10个项目几乎都是HashMaps。我会理解GC不会在方法结束时收集这些引用,因为我是一个多线程的ndk应用程序。但是DeleteLocalRef应该有效。

修复: 最后我发现从jni调用到我编写的java方法创建HashMap很好,然后引用是免费的。拥有一个java函数似乎很疯狂,它实际上只返回一个新的HashMap,但现在它的工作原理我和它一起生活:)