【问题标题】:jni table overflow even after deleteLocalRef即使在 deleteLocalRef 之后 jni 表也会溢出
【发布时间】:2014-12-09 22:19:54
【问题描述】:

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

这是我的代码:

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

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

pJNIEnv->DeleteLocalRef(pJNIData);

我已经阅读了一些建议,但没有一个有效!尽管有DeleteLocalRef,但它无法正常工作。该函数用于一个探查器,它实际上调用所有函数...

【问题讨论】:

  • 你确定这是填满你的参考表的代码吗?当您使用一个常量硬编码 pJNIData 时问题会消失吗?
  • @vtmarvin 不确定。这对参考表有影响吗? --> JNIEnv* pJNIEnv = profilerGetJNIEnv(); if(!pJNIEnv) { LOGE("Profiler ERROR: Java Environment is missing (null)!");返回; }

标签: android reference java-native-interface overflow


【解决方案1】:

我在调用 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 文档 dalvik/docs/jni-tips.html 并找到“本地与全局参考”部分)

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

【讨论】:

    【解决方案2】:

    我想我会加入以防万一其他人遇到这个问题。这是一个奇怪的案例,让我困惑了好几个小时!

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

    现在在 c++ 方法中,我使用 find class 和 getmethodid 将构造函数获取到 HashMap 并调用它以获取新的 HashMap 实例。然后我使用 jni 调用从 c++ 端填充 HashMap。到目前为止,一切都很好。 然后我将 HashMap 传递给 java 代码,一切都按预期工作。一旦 java 代码返回,我在 HashMap 上调用 DeleteLocalRef。没有抛出错误,但引用没有被删除。

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

    解决方法: 最后我发现从 jni 调用创建 HashMap 到我编写的 java 方法很好,然后引用是免费的。拥有一个实际上只返回一个新的 HashMap 的 java 函数似乎很疯狂,但它确实有效,所以现在我正在使用它:)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-07-09
      • 1970-01-01
      • 2021-01-02
      • 2018-11-25
      • 2014-06-30
      • 1970-01-01
      • 2016-07-09
      相关资源
      最近更新 更多