应用报未知错误

应用安装好连接电脑就能看错误信息

一般会是so库问题

怎么解决:so升级,so打包时间过老,不适合现在的种种环境,上网上搜索。

JNI ERROR (app bug): local reference table overflow (max=512)_Android


JNI ERROR (app bug): local reference table overflow (max=512)_Java_02


 JNI ERROR (app bug): local reference table overflow (max=512)

  看错误信息,应该本地指针块最大只要512个,当平凡调用之后,可能越界了,超出了范围,导致异常。

当线程从 Java 环境切换到 native code 上下文时(J2N),JVM 会分配一块内存,创建一个 Local Reference 表,这个表用来存放本次 native method 执行中创建的所有的 Local Reference。每当在 native code 中引用到一个 Java 对象时,JVM 就会在这个表中创建一个 Local Reference。比如我们调用 NewStringUTF() 在 Java Heap 中创建一个 String 对象后,在 Local Reference 表中就会相应新增一个 Local Reference。运行 nativemethod 的线程的堆栈记录着 Local Reference 表的内存位置,Local Reference 表中存放 JNI Local Reference,实现 Local Reference 到 Java 对象的映射。native method 代码间接访问 Java 对象。通过线程堆栈中的记录着 Local Reference 表的内存位置的指针定位相应的 Local Reference 的位置,然后通过相应的 Local Reference 映射到 Java 对象。

当 nativemethod 引用一个 Java 对象时,会在 Local Reference 表中创建一个新 Local Reference。在 Local Reference 结构中写入内容,实现 Local Reference 到 Java 对象的映射。 

native method 调用 DeleteLocalRef() 释放某个 JNI Local Reference 时,首先通过线程堆栈中的记录着 Local Reference 表的内存位置的指针定位相应的 Local Reference 在 Local Ref 表中的位置,然后从 Local Ref 表中删除该 Local Reference,也就取消了对相应 Java 对象的引用(Ref count 减 1)。 

当越来越多的 LocalReference 被创建,这些 Local Reference 会在 Local Ref 表中占据越来越多内存。当 Local Reference 太多以至于 Local Ref 表的空间被用光,JVM 会抛出异常,从而导致 JVM 的崩溃。

    产生Local Reference的操作有: 
1.FindClass 
2.NewString/ NewStringUTF/NewObject/NewByteArray 
3.GetObjectField/GetObjectClass/GetObjectArrayElement 
4.GetByteArrayElements和GetStringUTFChars

    解决方法: 
在native method中引用完java对象后及时调用env->DeleteLocalRef方法手动释放本地引用 
如果native method返回java对象就不需要手动release,因为java会自动回收

但通过JNI传递对象数组时,由于需要在一个for循环中将C++对象数组成员中的每一个元素通过SetObjectField与java对象的元素进行对应,并调用SetObjectArrayElement将对象添加到数组中,期间可能会不断生成local reference,但是不能在循环中手动release,最终引起local reference内存泄露,因此针对与这种情况可以将对象数组分批传递

    举例如下:   

     1、当java和c回调传的参数过多的时候,会出现内存泄露问题, 列如程序运行一段时间之后,莫名的出现如下错误JNI ERROR (app bug): local reference table overflow (max=512) Failed adding to JNI local ref table (has 512 entries) VM aborting  

    2、 引起这个bug的原因有如下几个: 

    上层传递参数String 给下层C语言,当底层使用完数据之后,一定要掉用ReleaseStringUTFChars接口将内存释放掉,不然当传递次数多了之后会导致系统奔溃 

JNIEXPORT jint JNICALL test_string(JNIEnv *env, jobject obj,jstring j_usrname,jstring j_passwd,jint j_host_id) 
{  
int usr_id =1; 
const char *usrname =  env->GetStringUTFChars (j_usrname, NULL);  LOGD("usrname = %s",usrname); 
env->ReleaseStringUTFChars (j_usrname, usrname);  
return 1; 

3、底层jni里面C语言接口调用上层java的方法时候,一定要释放obj类,不然也会导致系统奔溃,如下列子: 
底层子线程当中要调用上层的java的方法  
3.1在cpp接口程序里面定义全局变量 JavaVM *g_jvm=NULL; jobject g_obj = NULL; 
3.2在创建线程函数之前,给这两个变量赋值 

JNIEXPORT jint JNICALL init(JNIEnv *env, jobject obj,jint mode) 
{    
env->GetJavaVM(&g_jvm); 
g_obj = env->NewGlobalRef(obj);    pthread_t tid; 
pthread_create(&tid,NULL,testjni,NULL); 

3.3在线程函数里面调用上层的一个void fun(int a);方法  (注:只要在jni底层,除了自己用onload映射出来接口相对于整个APP来说是主线程函数以外,其它c函数接口都视为子线程函数) 

void *testjni(void *arg) 
{
JNIEnv *env;
jmethodID met;
jclass cls;
while(1)
{
if(g_jvm->AttachCurrentThread(&env, NULL) != JNI_OK)
{
LOGD("%s: AttachCurrentThread() failed", __FUNCTION__);
return NULL;
}
cls = env->GetObjectClass(g_obj);
met =env->GetMethodID(cls, "fun","(I)V");
env->CallVoidMethod(g_obj, met, 10);
env->DeleteLocalRef(g_obj); //注意必须释放缓存数据 sleep(1);
}
return NULL;
}