Почему я не должен снова использовать jclass и/или jmethodID в JNI?

Это - вопрос, связанный с предыдущим сообщением, но это сообщение было решено, и теперь я хотел изменить направление вопроса.

При работе с JNI необходимо спросить JNIEnv объект для jclass и jmethodID для каждого класса и метода, который будет использоваться в коде C/C++. Только, чтобы быть ясным, я хочу вызвать конструкторов Java или методы от C/C++.

Так как коммуникация от Java до C/C++ (и наоборот) является дорогостоящей, я первоначально думал, что один способ минимизировать это состоял в том, чтобы снова использовать jclass и 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);
    }
}

Проблема состоит в том, что я продолжил использовать этот шаблон и получил отказ сегментации, который был только решен не снова использованным это переменные (это было решением предыдущего сообщения).

Вопросы:

  • Почему это недопустимо к повторному использованию jclass и jmethodID через различные функции JNI? Я думал, что это оценивает, всегда было то же.
  • Только для любопытства: что влияние/издержки инициализации все необходимо jclass и jmethodID для каждой функции JNI?

35
задан Community 23 May 2017 в 11:47
поделиться

3 ответа

Правила здесь ясны. Значения идентификатора метода и идентификатора поля навсегда. Вы можете повесить на них. Поиски занимают некоторое время.

JClass , с другой стороны, обычно является локальной ссылкой . Местная ссылка выживает максимум, продолжительность единого вызова функции JNI.

Если вам нужно оптимизировать, вы должны задать JVM, чтобы сделать глобальную ссылку для вас. Нередко приобретать и поддерживать ссылки на общие классы, такие как 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();
    }
}
58
ответ дан 27 November 2019 в 06:54
поделиться

Внутри jni_onload , нужно использовать newglobalref На значениях jclass значений, возвращаемых FindClass , прежде чем их кэшировать.

Затем внутри jni_onunload Вы звоните DELETEGLOBALREF .

7
ответ дан 27 November 2019 в 06:54
поделиться

В мире JDBC обычной практикой (в соответствии с JDBC API) является использование Class # forName () для загрузки драйвера JDBC. Драйвер JDBC должен зарегистрироваться в DriverManager внутри статического блока:

package com.dbvendor.jdbc;

import java.sql.Driver;
import java.sql.DriverManager;

public class MyDriver implements Driver {

    static {
        DriverManager.registerDriver(new MyDriver());
    }

    public MyDriver() {
        //
    }

}

Вызов Class # forName () выполнит все статические инициализаторы . Это путь, что DriverManager может найти соответствующий драйвер среди зарегистрированных драйверов по URL-адресу подключения во время getConnection () , который примерно выглядит следующим образом:

public static Connection getConnection(String url) throws SQLException {
    for (Driver driver : registeredDrivers) {
        if (driver.acceptsURL(url)) {
            return driver.connect(url);
        }
    }
    throw new SQLException("No suitable driver");
}

Но также были драйверы JDBC, начиная с хорошо известного примера org.gjt.mm.mysql.Driver , который неправильно регистрируется внутри Constructor вместо статического блока:

package com.dbvendor.jdbc;

import java.sql.Driver;
import java.sql.DriverManager;

public class BadDriver implements Driver {

    public BadDriver() {
        DriverManager.registerDriver(this);
    }

}

Единственный способ заставить его работать динамически - это вызвать newInstance () после этого! Иначе вы столкнетесь с первого взгляда необъяснимым «SQLException: нет подходящего драйвера». Опять же, это ошибка в драйвере JDBC, а не в вашем коде. В настоящее время ни один драйвер JDBC не должен содержать эту ошибку. Таким образом, вы можете (и должны) оставить newInstance () .

-121--665719-

Есть JLexPHP: https://github.com/wez/JLexPHP/blob/master/jlex.php

Я его не использовал, но есть такой: http://pear.php.net/package/PHP_ParserGenerator , который создает PHP-анализатор из грамматики Lemon . Проект, кажется, неактивен.

Я также нашел этот проект: http://code.google.com/p/antlrphpruntime/ , в котором используется Antlr . Опять неактивно, хотя.

-121--1341508-

Поскольку я помню, что jclass является локальным по отношению к вызывающему методу, его нельзя кэшировать, однако идентификатор метода может быть. Для получения дополнительной информации см. http://java.sun.com/javase/6/docs/technotes/guides/jni/spec/design.html .

Извините, я не знаю про аспект производительности, каждый раз, когда я использовал JNI, он был незначительным по сравнению с задачей.

4
ответ дан 27 November 2019 в 06:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: