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

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

应用报未知错误



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


一般会是so库问题


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


image.png


image.png


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; 
}


目录
相关文章
|
2月前
Error:Execution failed for task ':app:processDebugManifest'. > Manifest merger failed with multiple
Error:Execution failed for task ':app:processDebugManifest'. > Manifest merger failed with multiple
13 1
|
7天前
|
Java 数据库连接 Spring
【SpringBoot】Error starting ApplicationContext. To display the conditions report re--run your app
【SpringBoot】Error starting ApplicationContext. To display the conditions report re--run your app
39 0
|
2月前
Error:Execution failed for task ':app:javaPreCompileDebug'. > Annotation processors must be explicit
Error:Execution failed for task ':app:javaPreCompileDebug'. > Annotation processors must be explicit
49 0
|
2月前
|
缓存 Java 开发工具
Error:Execution failed for task ‘:app:preDebugAndroidTestBuild’. Conflict with dependency ‘com.andr
Error:Execution failed for task ‘:app:preDebugAndroidTestBuild’. Conflict with dependency ‘com.andr
9 1
|
2月前
|
Java 数据库 索引
GreenDao,clearIdentityScope报错Error:Execution failed for task ':app:compileDebugJavaWithJavac'. > Com
GreenDao,clearIdentityScope报错Error:Execution failed for task ':app:compileDebugJavaWithJavac'. > Com
16 1
|
5月前
Error:express-session deprecated undefined resave option; provide resave option app.js:17:10
Error:express-session deprecated undefined resave option; provide resave option app.js:17:10
Error:express-session deprecated undefined resave option; provide resave option app.js:17:10
|
12月前
|
Android开发
The application could not be installed: INSTALL_FAILED_TEST_ONLY. Android App包安装失败(Bug记录)
The application could not be installed: INSTALL_FAILED_TEST_ONLY. Android App包安装失败(Bug记录)
|
数据库 Android开发
AndroidQ(10.0) 自带音乐APP正在扫描中bug修改
AndroidQ(10.0) 自带音乐APP正在扫描中bug修改
75 0
|
Web App开发 移动开发 前端开发
帮前端朋友解决下电网手持仪app bug
帮前端朋友解决下电网手持仪app bug
帮前端朋友解决下电网手持仪app bug
error LNK2005: 已经在 app_launcher.obj 中定义
error LNK2005: 已经在 app_launcher.obj 中定义
77 0