这是与以前的帖子有关的问题,但是此帖子已解决,现在我想更改问题的方向。
当与工作JNI,有必要询问JNIEnv对象jclass和jmethodID用于将在C / C 代码中使用每个类和方法。为了清楚起见,我想从C / C 调用Java构造函数或方法。
JNIEnv
jclass
jmethodID
由于从Java到C / C ++的通信成本很高(反之亦然),因此我最初认为使这种情况最小化的一种方法是重用jclassand jmethodID。因此,我将该实例保存在全局变量中,如下所示:
jclass someClass = NULL; jmethodID someMethod = NULL; JNIEXPORT jobject JNICALL Java_example_method1(JNIEnv *env, jobject jobj) { // initialize someClass and someMethod if they are NULL // use someClass and someMethod to call java (for example, thru NewObject) } JNIEXPORT jobject JNICALL Java_example_method2(JNIEnv *env, jobject jobj) { // initialize someClass and someMethod if they are NULL // use someClass and someMethod to call java again }
一个更具体(且有用)的示例,我用它从JNI函数中的任何位置抛出异常:
jclass jniExceptionClass = NULL; void throwJavaException(JNIEnv *env, const char* msg) { if (!jniExceptionClass) { jniExceptionClass = env->FindClass("example/JNIRuntimeException"); } if (jniExceptionClass) env->ThrowNew(jniExceptionClass, msg); } }
问题是我继续使用此 模式 并遇到了分段错误,只能通过不重复使用此变量来解决(这是上一篇文章的解决方案)。
问题是:
这里的规则很明确。方法ID和字段ID的值是永远不变的。您可以挂在他们身上。查找需要一些时间。
jclass另一方面,通常是 本地参考 。本地引用最多只能在一次调用JNI函数的过程中保留下来。
如果需要优化,则必须要求JVM为您提供全局引用。获取并保留对诸如的通用类的引用并不少见java.lang.String。
java.lang.String
当然,持有此类对类的引用将防止它(类)被垃圾回收。
jclass local = env->FindClass(CLS_JAVA_LANG_STRING); _CHECK_JAVA_EXCEPTION(env); java_lang_string_class = (jclass)env->NewGlobalRef(local); _CHECK_JAVA_EXCEPTION(env); env->DeleteLocalRef(local); _CHECK_JAVA_EXCEPTION(env);
检查宏调用:
static inline void check_java_exception(JNIEnv *env, int line) { UNUSED(line); if(env->ExceptionOccurred()) { #ifdef DEBUG fprintf(stderr, "Java exception at rlpjni.cpp line %d\n", line); env->ExceptionDescribe(); abort(); #endif throw bt_rlpjni_java_is_upset(); } }