转自:https://blog.csdn.net/u014411863/article/details/104725516
由于最近需要写一些jni代码,当然也踩了一些坑,现在梳理一下;写jni访问java层时如果FindClass失败,轻则会导致访问java层的方法失败,处理不当时会导致native层崩溃。
究其原因一般由两种:
原因一:
java类名称字符串的格式错误导致,需要注意以下几点:
1、JNI 类名称以软件包名称开头,并用斜线分隔,例如 java/lang/String。
2、果您要查找某个数组类,则需要以适当数量的英文方括号开头,并且还必须用“L”和“;”将该类括起来,因此 String 的一维数组将是 [Ljava/lang/String; 。
3、查找java层的内部类,需要在外部类签名的基础上使用 T”);
这种情形通常比较简单可以比较快速的定位出来,总的来说就是类签名书写错误导致的问题;
原因二
另一种情况通常出现线多线程中,也就是通常说的多线程FindClass失败问题,或则从native线程调起java层中,但二者出错的原理一致,
android开发者文档上给出的解释大致如下:
FindClass 要在你的代码关联的类加载器中启动类搜索。它会检查调用堆栈,如果你自行创建的线程,这时应用中没有堆栈帧。如果从此线程调用 FindClass,JavaVM 会在“系统”类加载器(而不是与应用关联的类加载器)中启动,因此尝试查找特定于应用的类将失败。
通俗点来来说就是:
JNI 中所有的 findclass 都必须是java调用下来才有效,由别的native线程(C++)直接调起时,由于没有 java 堆栈是不能找到 java的 class的,会导致findClass失败;
解决该问题的方式:
在首次从java层调用下来时,在FindClass成功后,将 jclass对象进行newGlobalRef 保存起来,后面再次使用时使用该成员变量即可;
参考文档:
https://developer.android.com/training/articles/perf-jni#faq_FindClass