Tengo un problema con JNI que me ha tomado todo el día y que probablemente me volverá loco si no pido ayuda.JNI Error de bus después de mover la creación de objetos a otro método
En dos frases: Llamo un NewObject desde un método JNI y funciona bien, pero cuando moví este código a otro método, se bloquea.
Más detalles:
que tienen esta clase simple, y quieren crear instancias de ella desde el ++ código JNI C/C:
package example;
public class ModelDetails {
public ModelDetails() { ... }
}
La clase con el método nativo es tan sigue:
package example;
public class JNIWrapper {
public native ModelDetails getModelDetails() throws SomeException;
}
El siguiente código funcionó muy bien:
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;
}
Sin embargo, ya que tengo que hacer un montón de cosas en esta función Java_example_JNIWrapper_getModelDetails
, decidí mover la creación de este objeto a otra función:
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;
}
De esta manera, en Java_example_JNIWrapper_getModelDetails
acabo de llamar fillModelDetails(env, jobj);
El problema es que ahora recibo un error de bus en la línea NewObject
.
Invalid memory access of location 0x9 eip=0x475fe1
Pregunta: ¿Alguien sabe por qué no debería estar llamando a un constructor de otro método? Parece realmente extraño.
Gracias por cualquier sugerencia, idea, comentarios ...
Editar:
Acabo de añadir -Xcheck:jni
y dio este mensaje:
FATAL ERROR in native method: Bad global or local ref passed to JNI
at example.JNIWrapper.getModelDetails(Native Method)
Así que este me dio la idea de que el problema podría deberse al uso del constructor y la identificación de clase de una variable global. Moví estas declaraciones a una variable local en el método JNI y funciona.
Esto realmente me asombra porque he estado utilizando estas variables globales desde hace un tiempo y nunca he tenido ningún problema ... ¿qué podría estar causando este problema?
debe adjuntar un depurador y saber exactamente donde está recibiendo el fallo. – bmargulies
Lo hice, está exactamente en la llamada NewObject. – YuppieNetworking
¿Cuáles fueron los valores de env, modelDetailsClass y mid? ese '9' sugiere un 0 en env. – bmargulies