JNI跨线程使用JNIEnv报错:调用FindClass触发检测错误原因咨询
错误原因分析:JNI跨线程使用JNIEnv导致的JNI DETECTED ERROR
错误核心原因
错误日志明确指出:
java_vm_ext.cc:579] JNI DETECTED ERROR IN APPLICATION: thread Thread[21,tid=15479,Native,Thread*=0x7d932413a0,peer=0x12f00038,"ImageReader-640x480f23u3m2-15444-0"] using JNIEnv* from thread Thread[1,tid=15444,Runnable,Thread*=0x7d931f4be0,peer=0x71d8ae98,"main"]
JNIEnv是线程绑定的资源,每个线程只能使用自己专属的JNIEnv实例,绝对不能跨线程直接复用其他线程的JNIEnv指针。
代码问题分析
- 在
callJavaFun函数中,你传入的jniEnv是来自主线程(Thread[1])的实例,但这个函数实际是在ImageReader对应的Native线程(Thread[21])中执行的,跨线程使用JNIEnv触发了虚拟机的错误检测。 - 而
Java_com_test_testQ_Yolov8Ncnn_test是标准的JNI入口函数,它的env参数是当前调用线程(主线程)的专属JNIEnv,所以执行不会有异常。
正确处理方式(补充)
如果需要在非JNI入口的线程中调用Java方法,应该通过全局保存的JavaVM实例获取当前线程的JNIEnv:
void callJavaFun( JNIEnv *jniEnv, jobject thiz, JavaVM *jniGvm, jmethodID methodID, jclass globalClass, cv::Mat &rgb ) { JNIEnv *currentEnv = nullptr; // 附加当前线程到JVM并获取专属JNIEnv jint result = jniGvm->AttachCurrentThread(¤tEnv, nullptr); if (result == JNI_OK) { jclass clazz = currentEnv->FindClass("com/test/testQ/Yolov8Ncnn"); jmethodID methodID = currentEnv->GetMethodID(clazz, "test", "()V"); if (methodID != NULL) { currentEnv->CallVoidMethod(thiz, methodID); } // 如果是临时创建的Native线程,需要执行detach;JVM管理的线程无需此操作 jniGvm->DetachCurrentThread(); } }
内容的提问来源于stack exchange,提问作者Mustafa Maden
相关产品推荐
相关产品推荐

