2016-12-25 4 views
2

Java JNIでMethodIdとJClassをキャッシュしようとしましたが、キャッシュされた値を使用するとEXE_BAD_ACCESSが発生しました。関数を使用してインラインで値を要求すると、エラーは消えてしまいました。私はグローバルな参照を使う必要があると分かりましたが、これはsegfaultを解決していません。JNIクラスID 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

しかし、キャッシュされたクラスを実行した場合、それがセグメンテーションフォルトを与えます。

V [libjvm.dylib + 0x309bcf] alloc_object(_jclass *、スレッド*)+ 0x15の

OSは、Mac 10.12です。 JDK 1.8.0_25。

これまでのテストではシングルスレッド化されており、JNI envも同じです。 ENVの

印刷記述:(JNIEnvの*)ENVのENV = 0x00007fcc3e0011e8 印刷記述:(JNIEnvの*)ENV = 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; 
}