现象:当使用JNI传输很多数据时会出现JNI ERROR (app bug): local reference table overflow (max=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内存泄露,因此针对与这种情况可以将对象数组分批传递
————————————————
版权声明:本文为CSDN博主「xpz445094213」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/xpz445094213/article/details/46633889