创建Java对象时JVM崩溃:构造函数存在却提示找不到
解决JNI创建String对象时JVM崩溃的问题
问题根源分析
你遇到的崩溃看似是找不到构造函数,但实际代码里有两个致命问题:
野指针引用
原代码中this->object = &newObject;是严重错误:newObject是构造函数内的局部栈变量,函数执行结束后这个变量会被销毁,保存它的地址会让this->object变成野指针。后续对这个指针的任何操作都会直接导致JVM崩溃,甚至可能掩盖真正的错误信息(比如GetMethodID失败的问题)。缺少JNI错误检查
调用GetMethodID和NewObjectV后没有判断返回值是否为NULL,也没有检查JNI异常。如果GetMethodID因为类引用错误(比如javaClass->getClass()没拿到正确的java.lang.String类)等原因失败,直接调用NewObjectV会触发崩溃。
修复后的代码示例
1. 修正JavaObject构造函数
JavaObject(jclass klass, const char *signature, ...) { std::cout << "constructing" << std::endl; va_list arg; va_start(arg, signature); // 获取构造函数ID并检查错误 jmethodID constructor = client->env->GetMethodID(klass, "<init>", signature); if (constructor == nullptr) { if (client->env->ExceptionCheck()) { client->env->ExceptionDescribe(); // 打印JNI异常详情 client->env->ExceptionClear(); } std::cerr << "Failed to get String constructor method ID" << std::endl; this->object = nullptr; va_end(arg); return; } // 创建对象并检查错误 jobject newObject = client->env->NewObjectV(klass, constructor, arg); if (newObject == nullptr) { if (client->env->ExceptionCheck()) { client->env->ExceptionDescribe(); client->env->ExceptionClear(); } std::cerr << "Failed to create String object" << std::endl; this->object = nullptr; va_end(arg); return; } // 保存全局引用(如果需要长期持有对象),避免局部引用被回收 this->object = client->env->NewGlobalRef(newObject); // 释放临时局部引用 client->env->DeleteLocalRef(newObject); va_end(arg); }
2. 修正String类构造函数
确保获取的是正确的java.lang.String类,建议直接用FindClass替代javaClass->getClass(),避免类引用错误:
String(jcharArray v1) : JavaObject(client->env->FindClass("java/lang/String"), "([C)V", v1) {}
关键注意事项
- JNI中局部引用(比如
NewObjectV返回的newObject)会在当前JNI方法返回后被JVM自动回收,如果你的JavaObject需要长期持有对象,必须调用NewGlobalRef创建全局引用,用完后记得调用DeleteGlobalRef释放。 - 任何JNI函数调用后都要检查返回值和JNI异常,这是排查JNI问题的核心手段。
内容的提问来源于stack exchange,提问作者Derek Li
相关产品推荐
相关产品推荐

