代码之家  ›  专栏  ›  技术社区  ›  YuppieNetworking

将对象创建移动到其他方法后发生JNI总线错误

  •  5
  • YuppieNetworking  · 技术社区  · 16 年前

    我和JNI之间有一个问题,我花了一整天的时间,如果我不寻求帮助,可能会把我逼疯。

    用两个短语 :我从JNI方法调用NewObject,它工作正常,但是当我将此代码移动到另一个方法时,它会崩溃。

    更多细节:

    我有这个简单的类,我想从JNI C/C++代码中创建它的实例:

    package example;
    
    public class ModelDetails {
        public ModelDetails() { ... }
    }
    

    使用本机方法的类如下:

    package example;
    public class JNIWrapper {
         public native ModelDetails getModelDetails() throws SomeException;
    }
    

    以下代码工作得很好:

    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;
    }
    

    但是,因为在这个函数中我要做很多事情 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;
    }
    

    这样,在 java_-example_-jniwrapper_-getmodeldetails 我只是打电话 fillModelDetails(env, jobj);

    问题是现在我在 NewObject 线。

    Invalid memory access of location 0x9 eip=0x475fe1
    

    问题 : 有人知道我为什么不应该从另一个方法调用构造函数吗?看起来很奇怪。

    谢谢你的任何建议,想法,评论…


    编辑:

    我刚刚加入 -Xcheck:jni 得到这个错误:

    FATAL ERROR in native method: Bad global or local ref passed to JNI
    at example.JNIWrapper.getModelDetails(Native Method)
    

    所以这让我想到问题可能是由使用全局变量的构造函数和类ID引起的。我将这些声明移动到JNI方法中的一个局部变量中,它就工作了。

    这真的让我吃惊,因为我用这些全局变量已经有一段时间了,从来没有遇到过任何问题…是什么导致了这个问题?

    2 回复  |  直到 16 年前
        1
  •  4
  •   YuppieNetworking    16 年前

    我会回答这个问题,因为我发现了问题,但是关于重新使用 jclass jmethodID . 在那个方向上改变这个问题似乎没有组织性,所以我将打开另一条线索。

    解决方案是使用局部变量

    jclass    modelDetailsClass           = NULL;
    jmethodID modelDetailsConstMid        = NULL;
    

    而不是我以前使用的全局变量。

        2
  •  0
  •   Community Mohan Dere    8 年前
    推荐文章