Android ndk 为什么本地引用表溢出?

Android ndk 为什么本地引用表溢出?,android-ndk,java-native-interface,Android Ndk,Java Native Interface,我正试图找出如何解决当提示点数很高时发生在代码上的崩溃问题。我的测试每次都用530个提示项来重现它。每个提示的数据大小为1 你可以在下面看到我的代码。本质上,native\u update\u cue\u points是从java层调用的。这会触发从jni层到java层的多个调用。不知何故,这导致了表溢出。我想对静态java函数的每次调用都不会释放分配的字符串值,从而导致堆栈溢出 示例代码 static void native_update_cue_points(JNIEnv *env, jcl

我正试图找出如何解决当提示点数很高时发生在代码上的崩溃问题。我的测试每次都用530个提示项来重现它。每个提示的数据大小为1

你可以在下面看到我的代码。本质上,
native\u update\u cue\u points
是从java层调用的。这会触发从jni层到java层的多个调用。不知何故,这导致了表溢出。我想对静态java函数的每次调用都不会释放分配的字符串值,从而导致堆栈溢出

示例代码

static void native_update_cue_points(JNIEnv *env, jclass clazz)
{
    if (smpMediaPlayer)
    {
        std::list<Cue> cuePoints;

        smpMediaPlayer->getCuePoints(&cuePoints);

        for (std::list<Cue>::iterator it = cuePoints.begin(); it != cuePoints.end(); it++)
        {
            Cue cue = *it;

            java_update_cue_point(env, clazz, smFields.global_ref_thiz, 0, &cue);
        }
    }
}

static void java_update_cue_point (JNIEnv *env, jclass clazz, jobject thiz, int reqType, Cue *pCue)
{
    if (!pCue) {
        return;
    }

    jlong id = pCue->id;
    jint type = pCue->type;
    jint extra = pCue->extra;
    jlong pos = pCue->pos;
    jlong duration = pCue->duration;
    jobjectArray jkeys = NULL;
    jobjectArray jvalues = NULL;

    int dataSize = pCue->data.size();

    if (0 < dataSize)
    {
        jkeys = env->NewObjectArray(dataSize, env->FindClass("java/lang/String"), NULL);
        jvalues = env->NewObjectArray(dataSize, env->FindClass("[B"), NULL);

        int position = 0;
        for (std::map<std::string, std::string>::iterator it = pCue->data.begin(); it != pCue->data.end(); it++)
        {
            // set key
            env->SetObjectArrayElement(jkeys, position, env->NewStringUTF(it->first.c_str()));

            // set value
            jbyteArray byteArray = env->NewByteArray(it->second.length());
            env->SetByteArrayRegion(byteArray, 0, it->second.length(), (const signed char *)it->second.c_str());
            env->SetObjectArrayElement(jvalues, position, byteArray);
            env->DeleteLocalRef(byteArray);

            position++;
        }
    }

    // report update
    env->CallStaticVoidMethod(
                clazz,
                smFields.native_callback_add_cue_point,
                thiz,
                (jint)reqType, id, type, extra, pos, duration, jkeys, jvalues);
}
Stacktrace

JNI ERROR (app bug): local reference table overflow (max=512)
 local reference table dump:
   Last 10 entries (of 512):
       511: 0x13054090 java.lang.String[] (1 elements)
       510: 0x70732980 java.lang.Class<java.lang.String>
       509: 0x130517c0 java.lang.String "song_artist"
       508: 0x13054080 byte[][] (1 elements)
       507: 0x7079af18 java.lang.Class<byte[]>
       506: 0x13054070 java.lang.String[] (1 elements)
       505: 0x70732980 java.lang.Class<java.lang.String>
       504: 0x13051700 java.lang.String "song_artist"
       503: 0x12d17ff0 byte[][] (1 elements)
       502: 0x7079af18 java.lang.Class<byte[]>
   Summary:
       205 of java.lang.Class (2 unique instances)
       103 of java.lang.String[] (1 elements) (103 unique instances)
       102 of java.lang.String (102 unique instances)
       102 of byte[][] (1 elements) (102 unique instances)  
static void java_update_cue_point (JNIEnv *env, jclass clazz, jobject thiz, int reqType, Cue *pCue)
{
    jclass jstringClass = env->FindClass("java/lang/String");
}
JNI ERROR (app bug): local reference table overflow (max=512)
 local reference table dump:
   Last 10 entries (of 512):
       511: 0x70732980 java.lang.Class<java.lang.String>
       510: 0x70732980 java.lang.Class<java.lang.String>
       509: 0x70732980 java.lang.Class<java.lang.String>
       508: 0x70732980 java.lang.Class<java.lang.String>
       507: 0x70732980 java.lang.Class<java.lang.String>
       506: 0x70732980 java.lang.Class<java.lang.String>
       505: 0x70732980 java.lang.Class<java.lang.String>
       504: 0x70732980 java.lang.Class<java.lang.String>
       503: 0x70732980 java.lang.Class<java.lang.String>
       502: 0x70732980 java.lang.Class<java.lang.String>
   Summary:
       512 of java.lang.Class (1 unique instances)  

我怀疑您需要调用在这行代码中创建的Java
字符串
对象上的
DeleteLocalRef()

        env->SetObjectArrayElement(jkeys, position, env->NewStringUTF(it->first.c_str()));

您对
NewStringUTF()
的调用创建了一个带有本地引用的Java对象,您不会删除它。

您创建了太多的本地引用(两个用于类,两个用于对象数组,还有一些用于字符串和字节数组,每次运行
Java\u update\u cue\u point
)。VM只能处理有限数量的本地引用。有关某些文档,请参见“”。JNI函数文档中的“”部分也有一些详细信息。当本机方法返回时,VM将自动释放本地引用,但在像您这样的循环中,您必须使用
DeleteLocalRef
删除不再需要的引用


为了稍微优化一下,我的建议是在
native\u update\u cue\u points
的循环外执行两个
FindClass
调用,并将它们作为参数传递给
java\u update\u cue\u point
。这样,当
native\u update\u cue\u points
返回时,虚拟机将为您释放两个类对象引用,您可以通过不反复查找相同的类来节省处理时间。

谢谢您的回答。所以我不应该从我所读的内容中删除本地引用。然而,我确实尝试过,也尝试过jkeys和jvalues,但问题仍然存在(发布您尝试的代码。根据您发布的本地引用表转储,您的本地引用表中有很多
String
引用,从您发布的代码中,这些引用只能来自
NewStringUTF()
。保存
NewStringUTF()的返回值应该不难。)
在局部变量中,将局部变量用作第一个
SetObjectArrayElement()的参数
call,然后删除本地引用。嘿@Andrew,请查看我关于这个问题的更新。事情变得很奇怪…:/To add:i建议在
native\u update\u cue\u points
中执行循环外的
FindClass
调用,并将它们作为参数传递给
java\u update\u cue\u point
。这样您只需有两个类对象的引用,当
native\u update\u cue\u points
返回时,VM将为您释放这些类对象,并且您通过不反复查找相同的类来节省处理时间。@user2543253请将您的注释作为答案发布。我相信您的输入对我来说是对我的问题的有效答案。谢谢!返回obje如果你不想打电话,你就不必打电话了。
        env->SetObjectArrayElement(jkeys, position, env->NewStringUTF(it->first.c_str()));