Yup*_*ing 5 java java-native-interface
我有一个问题,JNI整天带我走,如果我不打电话求助,可能会让我感到疯狂.
在两个短语中:我从JNI方法调用NewObject并且它工作正常,但是当我将此代码移动到另一个方法时,它会崩溃.
更多细节:
我有这个简单的类,我想从JNI C/C++代码创建它的实例:
package example;
public class ModelDetails {
public ModelDetails() { ... }
}
Run Code Online (Sandbox Code Playgroud)
具有本机方法的类如下:
package example;
public class JNIWrapper {
public native ModelDetails getModelDetails() throws SomeException;
}
Run Code Online (Sandbox Code Playgroud)
以下代码非常好用:
jclass modelDetailsClass = NULL;
jmethodID modelDetailsConstMid = NULL;
JNIEXPORT jobject JNICALL Java_example_JNIWrapper_getModelDetails
(JNIEnv *env, jobject jobj) {
cout << "getModelDetails c++" << endl;
// ModelDetails class
if (!modelDetailsClass) { // reuse class
modelDetailsClass = env->FindClass("example/ModelDetails");
}
if (!modelDetailsClass) { // check if findclass was successful
throwJavaException(env, "Could not get class ModelDetails");
return NULL;
}
cout << "model detail class: " << modelDetailsClass << endl;
// constructor
if (!modelDetailsConstMid) { // reuse method id
modelDetailsConstMid = env->GetMethodID(modelDetailsClass, "<init>", "()V");
}
if (!modelDetailsConstMid) { // check if getmethodid was successful
throwJavaException(env, "Could not get ModelDetails constructor method id");
return NULL;
}
// create object
jobject mdetails = env->NewObject(modelDetailsClass, modelDetailsConstMid);
if (!mdetails) {
throwJavaException(env, "Could not create ModelDetails instance");
return NULL;
}
return mdetails;
}
Run Code Online (Sandbox Code Playgroud)
但是,由于我必须在这个函数中做很多事情Java_example_JNIWrapper_getModelDetails,所以我决定将这个对象的创建移动到另一个函数:
jobject fillModelDetails(JNIEnv *env, jobject jobj) {
cout << "fillModelDetails" << endl;
// ModelDetails class
if (!modelDetailsClass) { // reuse class
modelDetailsClass = env->FindClass("example/ModelDetails");
}
if (!modelDetailsClass) { // check if findclass was successful
throwJavaException(env, "Could not get class ModelDetails");
return NULL;
}
cout << "model detail class: " << modelDetailsClass << endl;
// constructor
if (!modelDetailsConstMid) { // reuse method id
modelDetailsConstMid = env->GetMethodID(modelDetailsClass, "<init>", "()V");
}
if (!modelDetailsConstMid) { // check if getmethodid was successful
throwJavaException(env, "Could not get ModelDetails constructor method id");
return NULL;
}
// create object
jobject mdetails = env->NewObject(modelDetailsClass, modelDetailsConstMid);
if (!mdetails) {
throwJavaException(env, "Could not create ModelDetails instance");
return NULL;
}
return mdetails;
}
Run Code Online (Sandbox Code Playgroud)
这样,Java_example_JNIWrapper_getModelDetails我只是打电话fillModelDetails(env, jobj);
问题是现在我NewObject在线路上遇到了总线错误.
Invalid memory access of location 0x9 eip=0x475fe1
Run Code Online (Sandbox Code Playgroud)
问题:有谁知道为什么我不应该从另一个方法调用构造函数?这看起来很奇怪.
感谢任何提示,想法,评论......
编辑:
我刚刚添加-Xcheck:jni并收到此错误:
FATAL ERROR in native method: Bad global or local ref passed to JNI
at example.JNIWrapper.getModelDetails(Native Method)
Run Code Online (Sandbox Code Playgroud)
所以这让我觉得问题可能是由于使用全局变量中的构造函数和类id引起的.我将这些声明移动到JNI方法中的局部变量,它可以工作.
这真让我感到惊讶,因为我从一段时间以来一直在使用这些全局变量,从来没有遇到任何问题......可能导致这个问题的原因是什么?
因为我发现了这个问题,所以我会回答这个问题,但是关于重新使用jclass和 的另一个问题仍然存在jmethodID。朝这个方向改变这个问题似乎没有组织性,所以我将打开另一个线程。
解决方案是使用局部变量
jclass modelDetailsClass = NULL;
jmethodID modelDetailsConstMid = NULL;
Run Code Online (Sandbox Code Playgroud)
而不是我之前使用的全局变量。