gpt4 book ai didi

java - JNI GetMethodID 在 native 线程中导致错误

转载 作者:太空宇宙 更新时间:2023-11-03 13:22:20 24 4
gpt4 key购买 nike

在 android 中,我使用 pthread_create 创建一个本地线程,然后在回调过程中,调用 FindClass 来获取一个 Java 类。但它不起作用。我从 android jni tips 得到提示我在 FindClass from any thread in Android JNI 中找到了解决方案

我像这样为我的项目修改它[编辑]

JavaVM* gJvm = nullptr;
static jobject gClassLoader;
static jmethodID gFindClassMethod;

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *pjvm, void *reserved) {
gJvm = pjvm; // cache the JavaVM pointer
auto env = getEnv();
//replace with one of your classes in the line below
auto randomClass = env->FindClass("com/example/RandomClass");
jclass classClass = env->GetObjectClass(randomClass);
auto classLoaderClass = env->FindClass("java/lang/ClassLoader");
auto getClassLoaderMethod = env->GetMethodID(classClass, "getClassLoader",
"()Ljava/lang/ClassLoader;");
gClassLoader = env->CallObjectMethod(randomClass, getClassLoaderMethod);
gClassLoader = env->NewGlobalRef(gClassLoader);
gFindClassMethod = env->GetMethodID(classLoaderClass, "loadClass",
"(Ljava/lang/String;)Ljava/lang/Class;");

//check. this is ok
jclass cls = env->FindClass("com/example/data/DataTest");
jmethodID methoID = env->GetMethodID(cls, "name", "()Ljava/lang/String;");
LOG_INFO("cls is %p\n", cls);

return JNI_VERSION_1_6;
}

JNIEnv* getEnv() {
JNIEnv *env;
int status = gJvm->GetEnv((void**)&env, JNI_VERSION_1_6);
if(status < 0) {
status = gJvm->AttachCurrentThread(&env, NULL);
if(status < 0) {
return nullptr;
}
}
return env;
}


jclass findClass(const char* name) {
JNIEnv *env = getEnv();
jclass resultClass = 0;
if(env)
{
resultClass = env->FindClass(name);
//it can not found class in native thread, use loadClass method
if (!resultClass)
{
LOG_INFO("can not find the class");
//return value is not null.
return static_cast<jclass>(env->CallObjectMethod(gClassLoader, gFindClassMethod, env->NewStringUTF(name)));
}
}
return resultClass;
}
.......
//thread callback
void *proc(void *)
{
JNIEnv *env = getEnv();
jclass cls = findClass("com/example/data/DataTest");
if (cls)
{
LOG_INFO("GetMethodID");
//crash
jmethodID methodID = env->GetMethodID(cls, "name", "()Ljava/lang/String;");
LOG_INFO("proc tag is %p\n", tag);
}
}
.....
pthread_create(&handle, NULL, proc, 0);
.....

程序在 env->GetMethodID 处退出。我收到此错误:

Invalid indirect reference 0x40d8bb20 in decodeIndirectRef.

如果我从 findClass 中删除 resultClass = env->FindClass(name);,就可以了。可以打印“proc tag is”。

//correct 
jclass findClass(const char* name) {
JNIEnv *env = getEnv();
jclass resultClass = 0;
if(env)
{
if (!resultClass)
{
return static_cast<jclass>(env->CallObjectMethod(gClassLoader, gFindClassMethod, env->NewStringUTF(name)));
}
}
return resultClass;
}

env->FindClass(name);env->CallObjectMethod to loadClass 之间有任何冲突吗?

这是一个错误吗?可以做些什么来解决这个问题?

最佳答案

不要这样做:

gClassLoader = env->CallObjectMethod(randomClass, getClassLoaderMethod);

特别是,永远不要将局部引用(CallObjectMethod 返回的内容)存储在局部变量以外的任何地方。

如果您想在获取局部引用的函数之外访问该值,则需要使用 NewGlobalRef 获取全局引用。一旦执行返回到该线程中的 VM,本地引用就会失效。

请参阅 JNI Tips 中的“本地和全局引用”部分文档。

关于java - JNI GetMethodID 在 native 线程中导致错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25782353/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com