为什么我不应该在JNI中重用jclass和/或jmethodID? [英] Why I should not reuse a jclass and/or jmethodID in JNI?
问题描述
这是一个与上一篇文章相关的问题,但这篇文章已经解决了,现在我想改变问题的方向。
This is a question related to a previous post, but this post was solved and now I wanted to change the direction of the question.
在与JNI合作时,有必要问 JNIEnv
对象为 jclass
和 jmethodID
为每个类和方法用于C / C ++代码。为了清楚起见,我想从C / C ++调用Java结构或方法。
When working with JNI, it is necessary to ask the JNIEnv
object for jclass
and jmethodID
for each class and method that will be used in the C/C++ code. Just to be clear, I want to call Java contructors or methods from C/C++.
由于从Java到C / C ++(反之亦然)的通信成本很高,我最初认为最小化这种方法的一种方法是重用 jclass
和 jmethodID
。因此,我将此实例保存在全局变量中,如下所示:
Since the communication from Java to C/C++ (and viceversa) is costly, I initially thought that one way to minimize this was to reuse the jclass
and jmethodID
. Therefore, I saved this instances in global variables as follows:
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函数中的任何地方抛出异常:
A more specific (and useful) example, which I use to throw exceptions from anywhere in my JNI functions:
jclass jniExceptionClass = NULL;
void throwJavaException(JNIEnv *env, const char* msg) {
if (!jniExceptionClass) {
jniExceptionClass = env->FindClass("example/JNIRuntimeException");
}
if (jniExceptionClass)
env->ThrowNew(jniExceptionClass, msg);
}
}
问题是我继续使用这个 pattern 并得到了一个只能通过不重用这个变量来解决的分段错误(这是上一篇文章的解决方案)。
The problem is that I continued to use this pattern and got a segmentation fault that was only solved by not-reusing this variables (this was the solution to the previous post).
问题是:
- 为什么重用
jclass
和jmethodID
通过不同的JNI函数?我认为这些值总是一样的。 - 只是出于好奇:初始化所有必要的
jclass
的影响/开销是多少?每个JNI函数jmethodID
?
- Why is it illegal to reuse the
jclass
andjmethodID
thru different JNI functions? I thought that this values were always the same. - Just for curiosity: what is the impact/overhead of initializing all necessary
jclass
andjmethodID
for each JNI function?
推荐答案
<这里的规则很清楚。方法ID和字段ID值是永远的。你可以挂在他们身上。查找需要一些时间。
The rules here are clear. Method ID and field ID values are forever. You can hang onto them. The lookups take some time.
jclass
,另一方面,通常是本地参考的。本地引用最多只能存储一次JNI函数的持续时间。
jclass
, on the other hand, is generally a local reference. A local reference survives, at most, the duration of a single call to a JNI function.
如果需要优化,则必须要求JVM创建全局给你参考。获取并保持对诸如 java.lang.String
之类的公共类的引用并不罕见。
If you need to optimize, you have to ask the JVM to make a global reference for you. It's not uncommon to acquire and keep references to common classes like java.lang.String
.
当然,持有对类的引用会阻止它(类)被垃圾收集。
Holding such a reference to a class will prevent it (the class) from being garbage-collected, of course.
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();
}
}
这篇关于为什么我不应该在JNI中重用jclass和/或jmethodID?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!