JNI错误总结

  最近公司里要用JNI技术,用java去调用已经写好的本地DLL库。之前自己也没接触过相关技术,其中花了大部分时间在调试改错上面,网上对于错误的解决方案也不多,现在项目接近完工,自己也该把其中碰到的一些问题进行一下汇总。

  1.相关命令:

   将包含native函数的java源代码生成JNI的.h头文件:  javah  -jni com.xxx.test  

   注意:test是编译后的.class文件,要写完整路径,该命令在com的上层目录下进行。更完整的命令为: javah -classpath . -jni com.xxx.test  注意中间的点号

   编写实现上面.h文件的.cpp代码后,生成dll目标文件:g++ -Wl,--kill-at -shared -o test1.dll test2.cpp 

   注意:test1.dll为生成的目标DLL,test2为cpp源文件。红色部分不可少,表示生成不带@的函数.

  

  2.如何将java里的string类型转换为C里的char*类型:

char* jstringTostring(JNIEnv* env, jstring jstr) //change type string into char*

{

    char* rtn = NULL;

    jclass clsstring = env->FindClass("java/lang/String");

    jstring strencode = env->NewStringUTF("utf-8");

    jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");

    jbyteArray barr= (jbyteArray)env->CallObjectMethod(jstr, mid, strencode);

    jsize alen = env->GetArrayLength(barr);

    jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);

    if (alen > 0)

    {

        rtn = (char*)malloc(alen + 1);

        memcpy(rtn, ba, alen);

        rtn[alen] = 0;

    }

    env->ReleaseByteArrayElements(barr, ba, 0);

    return rtn;

}

  

  

  3.如何将C里的char*类型转换为java里的string类型:

jstring stoJstring(JNIEnv* env, const char* pat)//change type char* into string

{

    jclass strClass = env->FindClass("Ljava/lang/String;");

    jmethodID ctorID = env->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V");

    jbyteArray bytes = env->NewByteArray(strlen(pat));

    env->SetByteArrayRegion(bytes, 0, strlen(pat), (jbyte*)pat);

    jstring encoding = env->NewStringUTF("utf-8");

    return (jstring)env->NewObject(strClass, ctorID, bytes, encoding);

}

  

  4.JNI里如何返回arraylist类型:

        jclass cls_ArrayList = env->FindClass("java/util/ArrayList");  

        jmethodID construct = env->GetMethodID(cls_ArrayList,"<init>","()V");//注意第二个参数为<init>,网上有些资料写着为空或者<init></init>是错的。  

        jobject obj_ArrayList = env->NewObject(cls_ArrayList,construct,"");  

        jmethodID arrayList_add = env->GetMethodID(cls_ArrayList,"add","(Ljava/lang/Object;)Z"); //获得arraylist的add()方法 

        //User Object  

        jclass cls_user = env->FindClass("User"); //注意User所在路径要写完整,该加包名的地方要加上 

        //none argument construct function  

        jmethodID construct_user = env->GetMethodID(cls_user,"<init>","()V");  

        //new a object  

        jobject obj_user = env->NewObject(cls_user,construct_user,"");  

        //get method id  

        /* 

        jmethodID user_setId = env->GetMethodID(cls_user,"setId","(J)V"); 

        jmethodID user_setUserName = env->GetMethodID(cls_user,"setUserName","(Ljava/lang/String;)V"); 

        jmethodID user_setMan = env->GetMethodID(cls_user,"setMan","(Z)V"); 

        jmethodID user_setAge = env->GetMethodID(cls_user,"setAge","(I)V"); 

        */  

        int i;  

        for(i=0;i<10;i++){  

        //new a object  

        jobject obj_user = env->NewObject(cls_user,construct_user,"");  

        //get field id  

        jfieldID user_id = env->GetFieldID(cls_user,"id","J");  

        jfieldID user_name = env->GetFieldID(cls_user,"userName","Ljava/lang/String;");  

        jfieldID user_isMan = env->GetFieldID(cls_user,"isMan","Z");  

        jfieldID user_age = env->GetFieldID(cls_user,"age","I");  

        env->SetLongField(obj_user,user_id,i);  

        env->SetObjectField(obj_user,user_name,env->NewStringUTF("CC"));  

        env->SetBooleanField(obj_user,user_isMan,1);  

        env->SetIntField(obj_user,user_age,21);  

        env->CallObjectMethod(obj_ArrayList,arrayList_add,obj_user);  

        }  

        return obj_ArrayList;  

  

  5.对于碰到以下错误:

# A fatal error has been detected by the Java Runtime Environment:

#

# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x7c92100b, pid=596, tid=2080

#

# JRE version: 6.0_21-b07

# Java VM: Java HotSpot(TM) Client VM (17.0-b17 mixed mode, sharing windows-x86 )

# Problematic frame:

# C [ntdll.dll+0x100b]

#

# If you would like to submit a bug report, please visit:

# http://java.sun.com/webapps/bugreport/crash.jsp

# The crash happened outside the Java Virtual Machine in native code.

# See problematic frame for where to report the bug.

  一般都是由于你所写的JNI转换后的CPP实现代码有问题。可以关注下红色部分,若pc=0x00000000,则表示你要实现的native函数里传入了空指针void*或null。

  而如果你传入的参数还有结构体变量,那么这里的空值还要考虑结构体里的部分成员是否也为空,JNI里的函数是不允许传入空值的,这点网上的资料里都没有提,我也在这里卡了很久。但是你必须要传入空值,而且还要调用更下一层的DLL里的函数时,那就会报错,这时该怎么办呢?此时你可以在它们中间再加一过渡层(CPP文件)实现间接调用。  

 

  6.最后注意下JNI里的资源释放问题,若使用资源过多没有及时释放,也会有可能会报上面的错误。

  如:env->ReleaseStringUTFChars(xxx, xxx);

 

  至于其他问题网上都有就不写了。

你可能感兴趣的:(jni)