2016-12-25 6 views
2

Я попытался кэшировать MethodId и JClass в Java JNI, но я испытал EXE_BAD_ACCESS, когда использовал кешированные значения. Ошибка исчезла, когда я запросил значения inline с помощью функции, использующей их. Я понял, что мне нужно использовать глобальную ссылку, но это не решило segfault.Идентификатор класса JNI segfault

Связанная информация для кэширования JNI (слегка устаревшие подписи) - In JNI, how do I cache the class, methodID, and fieldIDs per IBM's performance recommendations?

Заголовок:

extern jclass java_class_boolean; 
extern jmethodID java_method_boolean; 

CPP:

jclass java_class_boolean; 
jmethodID java_method_boolean; 
.... 
void initStatic(JNIEnv* env){ 
    java_class_boolean = env->FindClass("java/lang/Boolean"); 
    if (java_class_boolean){ 
     env->NewGlobalRef(java_class_boolean); 
     java_method_boolean = env->GetMethodID(java_class_boolean, "<init>", "(Z)V"); 
    } 
} 

Использование (другой класс CPP, импортируя общий заголовок):

jclass bc = env->FindClass("java/lang/Boolean"); 
    jmethodID bm = env->GetMethodID(bc, "<init>", "(Z)V"); 

    std::cout << "\nClass new: "; 
    std::cout << bc; 
    std::cout << " Class old: "; 
    std::cout << java_class_boolean; 
    std::cout << "\nMethod new: "; 
    std::cout << bm; 
    std::cout << " Method old: "; 
    std::cout << java_method_boolean; 
    std::cout << "\n"; 
    result2 = env->NewObject(bc, bm, 1); 

Результат

Класс новый: 0x7fcce4430110 Класс старый: 0x7fcce6a23098 Метод новый: 0x7fcce471c288 Метод старый: 0x7fcce471c288

Но если работать с кешированной класса, он дает Segfault.

В [libjvm.dylib + 0x309bcf] alloc_object (_jclass *, резьба *) + 0x15

ОС Mac 10.12. JDK 1.8.0_25.

Также, что испытания пока только однопоточные, а JNI env - то же самое.

Описание Печать окр: (JNIEnv *) окр = 0x00007fcc3e0011e8 Описание Печать окр: (JNIEnv *) окр = 0x00007fcc3e0011e8

Оба initStatic и будущего использования находятся на "Тема 4" с тот же экземпляр env (передан JNI, а не кеширован). Существуют и другие потоки, но segfault и init находятся в одном потоке.

ответ

1

Проблема была в том, что я не понимал, что -> NewGlobalRef возвратил объект.

Я создал эту функцию для решения проблемы.

inline jclass find_class_global(JNIEnv* env, const char *name){ 
    jclass c = env->FindClass(name); 
    jclass c_global = 0; 
    if (c){ 
     c_global = (jclass)env->NewGlobalRef(c); 
     env->DeleteLocalRef(c); 
    } 
    return c_global; 
}