为什么我不应该在JNI中重用jclass和/或jmethodID? [英] Why I should not reuse a jclass and/or jmethodID in JNI?

查看:707
本文介绍了为什么我不应该在JNI中重用jclass和/或jmethodID?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个与上一篇文章相关的问题,但这篇文章已经解决了,现在我想改变问题的方向。

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 and jmethodID 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 and jmethodID 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆